Chapter 10 (in book v2) PBR challenge

I’m getting
3.0 meters is equal to 0.000000 feet and 118.1 inches.
as the result of using modf() instead of floor().

I know this isn’t right, but haven’t figured out what I did yet.

If anyone else tries this challenge, let me know if you figure out why I’m getting zero feet.

I got similar issue with solving the challenge, please somebody help me. Anything wrong with my code?
Note to the authors : I think you guys forgot to explain what the floor() function is, I had to do googling…

void metersToFeetAndInches(double meters, int *ftptr, double *inptr)
{
double inches;
unsigned int feet;
double rawFeet = meters * 3.218;
inches = modf(rawFeet, &feet) * 12.0;
*inptr = inches;
*ftptr = feet;
}

int main(int argc, const char * argv[])
{
double meters = 3.0;
unsigned int feet;
double inches;
metersToFeetAndInches(meters, &feet, &inches);
printf(“If you change %.1f meters to feet & inches, it should be %dfeets + %.3finches.\n”, meters, feet, inches);

return 0;

}

//Here is the result.

If you change 3.0 meters to feet & inches, it should be 0feets + 7.848inches.
Program ended with exit code: 0

The type of the second argument passed to the modf function should be double*, not unsigned int*.

Compare yours to this:

#import <Foundation/Foundation.h>

typedef double length_type;

void metersToFeetAndInches (length_type meters, length_type *ftptr, length_type *inptr)
{
    length_type inches;
    length_type feet;
    length_type rawFeet = meters * 3.218;
    inches = modf (rawFeet, &feet) * 12.0;
    *inptr = inches;
    *ftptr = feet;
}

int main (int argc, const char * argv[])
{
    length_type meters = 3.0;
    length_type feet;
    length_type inches;
    metersToFeetAndInches (meters, &feet, &inches);
    printf ("If you change %.1f meters to feet & inches, it should be %.1ffeets + %.3finches.\n", meters, feet, inches);
    
    return 0;
}

I took a similar approach, but left the foot as an unsigned integer like the original code in the book. All you have to do is cast the double as an int when assigning to the dereferenced pointer like this: *ftPtr = (int)feet;

#include <stdio.h>
#include <math.h>

void metersToFeetAndInches(double meters, unsigned int *ftPtr, double *inPtr)
{
    double inches, feet;
    double rawFeet = meters * 3.281;
    inches = modf(rawFeet, &feet) * 12.0;
    
    *ftPtr = (int)feet;
    *inPtr = inches;
    
    if (ftPtr) {
        printf("Storing %u to the address %p\n", *ftPtr, ftPtr);
    }
    
    if (inPtr) {
        printf("Storing %.2f to the address %p\n", *inPtr, inPtr);
    }
}


int main(int argc, const char * argv[])
{
    double meters = 3.0;
    unsigned int feet;
    double inches;
    
    metersToFeetAndInches(meters, &feet, &inches);
    printf("%.1f meters is equal to %d feet and %.1f inches.\n", meters, feet, inches);
    
    return 0;
}

@mbspears Thanks so much I was getting really frustrated. I was super close but I couldn’t find a solution to get past the whole *ftPtr = (int)feet; part. If you wouldn’t mind can please try to explain the whole term dereferencing. I have run across it a couple times in the book and I’m not quite yet grasping the concept of what it means. Thanks.

My head is spinning trying to figure out what’s wrong with my code. Maybe someone can figure it out if I post it:


void metersToFeetAndInches(double meters, double *ftPtr, double *inPtr)
{
    // This function assumes meters in non-negative.
    
    // Convert the number of meters into a floating-point
    double rawFeet = meters * 3.281; // e.g. 2.4536
    
    // How many complete feet as an unsigned int?
    double feet = modf(*ftPtr, inPtr);
    
    // Store the number of feet at the supplied address
    if (ftPtr) {
        printf("Storing %.0f to the address %p\n", feet, ftPtr);
        *ftPtr = feet;
    }
    
    
    // Calculate inches
    double fractionalFoot = rawFeet - feet;
    double inches = fractionalFoot * 12.0;
    
    // Store the number of inches at the supplied address
    if (inPtr) {
        
        printf("Storing %.2f to the address %p\n", inches, inPtr);
        *inPtr = inches;
    }
}

// MAIN
int main(int argc, const char * argv[])
{    
    double meters = 3.0;
    // unsigned int feet;
    // Challenge version of ^ this
    double feet;
    double inches;
    
    metersToFeetAndInches(meters, &feet, &inches);
    printf("%.1f meters is equal to %f feet and %.1f inches.\n", meters, feet, inches);
    
    return 0;
}

[quote=“Zachariah”]My head is spinning trying to figure out what’s wrong with my code. Maybe someone can figure it out if I post it:

[code]

void metersToFeetAndInches(double meters, double *ftPtr, double *inPtr)
{
// This function assumes meters in non-negative.

// Convert the number of meters into a floating-point
double rawFeet = meters * 3.281; // e.g. 2.4536

// How many complete feet as an unsigned int?
double feet = modf(*ftPtr, inPtr);

// Store the number of feet at the supplied address
if (ftPtr) {
    printf("Storing %.0f to the address %p\n", feet, ftPtr);
    *ftPtr = feet;
}


// Calculate inches
double fractionalFoot = rawFeet - feet;
double inches = fractionalFoot * 12.0;

// Store the number of inches at the supplied address
if (inPtr) {
    
    printf("Storing %.2f to the address %p\n", inches, inPtr);
    *inPtr = inches;
}

}

// MAIN
int main(int argc, const char * argv[])
{
double meters = 3.0;
// unsigned int feet;
// Challenge version of ^ this
double feet;
double inches;

metersToFeetAndInches(meters, &feet, &inches);
printf("%.1f meters is equal to %f feet and %.1f inches.\n", meters, feet, inches);

return 0;

}
[/code][/quote]

The main problem is you are passing your pointers into the modf function, instead what you want to do is pass rawFeet and a pointer to your feet variable and save that as inches. Here is what my metersToFeetAndInches function looks like for comparison:

[code]void metersToFeetAndInches(double meters, unsigned int *ftPtr, double *inPtr)
{
double rawFeet = meters * 3.281;
double feet;
double inches = modf(rawFeet, &feet) * 12.0;

if (ftPtr) {
    printf("Storing %.0f to the address %p\n", feet, ftPtr);
    *ftPtr = (unsigned int)feet;
}

if (inPtr) {
    printf("Storing %.2f to the address %p\n", inches, inPtr);
    *inPtr = inches;
}

}[/code]

@Sharks33

In chapter 9 under section “Getting the data at an address”, there’s a small paragraph that explains how the asterisk is used. Here’s how I understood that part after I read it: pointers are often referred to as references. When you create a pointer, you’re creating a reference to a data type. The pointer stores/references the address of that data type you just created. Now, when dereferencing the pointer, you’re wanting to assign (=) the actual data at that address. If you don’t dereference it, it will think you’re wanting to change the address the pointer is pointing to. Here’s some example code

int x = 1;
int *ptr = &x;

// if you wrote this, you’re assigning the address of x as 2
ptr = 2; <----- this does not make the value of x 2; it keeps the value of x 1 and assigns it to memory address 2

// if you wrote this, you’re assigning the number 2 as the data at the address the pointer is pointing to
*ptr = 2; <----this makes the value of x 2; it keeps the address of x the same

I think I have it figured out but I’m not 100% sure. I’m hoping what I wrote makes sense so that someone might read it and correct me if I’m wrong or tell me I have it right.

No, you can not change the address of x. What you can change is the value of x or value of ptr.

[quote=“ibex10”][quote]
int x = 1;
int *ptr = &x;

// if you wrote this, you’re assigning the address of x as 2
ptr = 2; <----- this does not make the value of x 2; it keeps the value of x 1 [color=#FF0000]and assigns it to memory address 2[/color]

// if you wrote this, you’re assigning the number 2 as the data at the address the pointer is pointing to
*ptr = 2; <----this makes the value of x 2; it keeps the address of x the same
[/quote]
No, you can not change the address of x. What you can change is the value of x or value of ptr.[/quote]

Thanks for the clarification. If I’m understanding it correctly now, changing the value of the pointer does not affect x at all; you’re just assigning the pointer a new value (in my case 2).

Took me about 40 mins but here is it

pastebin.com/tPWbmSta

Hello,
as for the challenge in chapter 10, I’m not sure which way is better:

[size=150]variant 1[/size]

to call the function passing variables

[code]void metersToFeetAndInches(double meters, double ftPtr, double inPtr){
double rawFeet = meters * 3.281;
inPtr = modf(rawFeet, &ftPtr) * 12.0;
}

int main(int argc, const char * argv[])
{

double meters = 3.0;
double feet;
double inches;

metersToFeetAndInches(meters, feet, inches);
printf("%.1d meters is equal to %.1d feet and %.3f inches.\n", (int)meters, (int)feet, inches);

return 0;

}[/code]

or

[size=150]variant 2[/size]

to pass their addresses only and declare new pointers in function’s params. By the way, though this version works as well, I’m still still unsure why the second parameter in modf should be ftPtr, but the results of modf are assigned to *inPtr. The only explanation I see, is that the ftPtr in this case represents (somehow) an address, which is required by modf, while the fraction part is assigned to *inPtr (and I don’t have a clue why we should write it with asterix - it’s already declared as a pointer in the function’s params, right?)… So, the code is working, but still many questions why :slight_smile:

[code]void metersToFeetAndInches(double meters, double *ftPtr, double *inPtr){
double rawFeet = meters * 3.281;
*inPtr = modf(rawFeet, ftPtr) * 12.0;
}

int main(int argc, const char * argv[])
{

double meters = 3.0;
double feet;
double inches;

metersToFeetAndInches(meters, &feet, &inches);
printf("%.1d meters is equal to %.1d feet and %.3f inches.\n", (int)meters, (int)feet, inches);

return 0;

}[/code]

Actually this code could fail as you are not doing a test for NULL before dereferencing ‘feet’ and ‘inches’ to the pointers. the reason we have the tests on ftPtr and inPtr is specifically for this reason. If the pointers don’t point to a valid address when you go to store a value in them the program will crash.

[quote=“mbspears”]I took a similar approach, but left the foot as an unsigned integer like the original code in the book. All you have to do is cast the double as an int when assigning to the dereferenced pointer like this: *ftPtr = (int)feet;

[code]
#include <stdio.h>
#include <math.h>

void metersToFeetAndInches(double meters, unsigned int *ftPtr, double *inPtr)
{
double inches, feet;
double rawFeet = meters * 3.281;
inches = modf(rawFeet, &feet) * 12.0;

*ftPtr = (int)feet;
*inPtr = inches;

if (ftPtr) {
    printf("Storing %u to the address %p\n", *ftPtr, ftPtr);
}

if (inPtr) {
    printf("Storing %.2f to the address %p\n", *inPtr, inPtr);
}

}

int main(int argc, const char * argv[])
{
double meters = 3.0;
unsigned int feet;
double inches;

metersToFeetAndInches(meters, &feet, &inches);
printf("%.1f meters is equal to %d feet and %.1f inches.\n", meters, feet, inches);

return 0;

}
[/code][/quote]

Variant 1 doesn’t work, and the reason why is that the arguments ftPtr and inPtr in your function (defined as variables, not pointers) only exist while the function is executing; the second the function completes those variables (arguments = variables) cease to exist. Running variant 1 returns 0 feet and 0 inches.

This is the whole purpose of “pass by reference”, it is a way of having functions return values to a calling routine by storing the contents in variables that had been declared in the calling routine, and it is done by using pointers to those variables.

As for your questions with variant 2 and modf():

  • The reason ftPtr works is that it is an address you are sending modf() (it is defined as *ftPtr in your function argument, which means it is a pointer), and that is what modf() expects.
  • The reason you need to use *inPtr is that modf() is returning a value, so you need to dereference inPtr as it is a pointer as defined in your function argument. A pointer stores an address, not a value.

Hope this helps…Ian

[quote=“burkanov”]Hello,
as for the challenge in chapter 10, I’m not sure which way is better:

[size=150]variant 1[/size]

to call the function passing variables

[code]void metersToFeetAndInches(double meters, double ftPtr, double inPtr){
double rawFeet = meters * 3.281;
inPtr = modf(rawFeet, &ftPtr) * 12.0;
}

int main(int argc, const char * argv[])
{

double meters = 3.0;
double feet;
double inches;

metersToFeetAndInches(meters, feet, inches);
printf("%.1d meters is equal to %.1d feet and %.3f inches.\n", (int)meters, (int)feet, inches);

return 0;

}[/code]

or

[size=150]variant 2[/size]

to pass their addresses only and declare new pointers in function’s params. By the way, though this version works as well, I’m still still unsure why the second parameter in modf should be ftPtr, but the results of modf are assigned to *inPtr. The only explanation I see, is that the ftPtr in this case represents (somehow) an address, which is required by modf, while the fraction part is assigned to *inPtr (and I don’t have a clue why we should write it with asterix - it’s already declared as a pointer in the function’s params, right?)… So, the code is working, but still many questions why :slight_smile:

[code]void metersToFeetAndInches(double meters, double *ftPtr, double *inPtr){
double rawFeet = meters * 3.281;
*inPtr = modf(rawFeet, ftPtr) * 12.0;
}

int main(int argc, const char * argv[])
{

double meters = 3.0;
double feet;
double inches;

metersToFeetAndInches(meters, &feet, &inches);
printf("%.1d meters is equal to %.1d feet and %.3f inches.\n", (int)meters, (int)feet, inches);

return 0;

}[/code][/quote]

is this code right anyone can check please ?

[code]
#include <stdio.h>
#include <math.h>

void metersToFeetAndInches(double meters, double *ftPtr, double *inPtr)
{
double rawFeet = meters * 3.281;

double feet;
double nF = modf(rawFeet, &feet);

if(ftPtr){
printf("storing %f to the address %p\n\n", nF, ftPtr);
*ftPtr = nF;
}
double inches = nF * 12.0;

if(inPtr){
printf("storing %.2f to the address %p\n\n", inches, inPtr);
*inPtr = inches;
}

}

int main(int argc, const char * argv[])
{
double meters = 3.0;
double feet;
double inches;

metersToFeetAndInches(meters, &feet, &inches);
printf("%.2f meters is %f feet and %.2f inches\n", meters, feet, inches);

}[/code]

Almost perfect.

But:

[quote]int main(int argc, const char * argv[]) { ... double feet; double inches; ... }[/quote]
Always initialize variables before using them:

int main (int argc, const char * argv[]) { ... double feet = 0; double inches = 0; ... }

[quote=“ibex10”]Almost perfect.

But:

[quote]int main(int argc, const char * argv[]) { ... double feet; double inches; ... }[/quote]
Always initialize variables before using them:

int main (int argc, const char * argv[]) { ... double feet = 0; double inches = 0; ... }[/quote]

Thank you sir.

//This is what I came up with. I had to change feet to the type float in order to use modf. I saw someone else used a work around to keep it an int. Any reason why just making it a float is a bad idea? Also, my code seems sparse compared to others. Any issues with the way I did it? Thanks!

#include <stdio.h>
#include <math.h>

int main(int argc, const char * argv[]) {

double meters = 3.0;
double feet, inches;
double rawFeet = meters * 3.281;
float fractionalFoot;

fractionalFoot = modf(rawFeet, &feet);
inches = fractionalFoot * 12;
printf("feet = %f, inches= %.2f\n", feet, inches);

return 0;

}

Output: feet = 9.000000, inches= 10.12

No. You did the right thing.

To make your code more readable, you can make const those variables that you are not going to change after the declaration:

#include <stdio.h>
#include <math.h>

int main (int argc, const char * argv[])
{
    const double meters = 3.0;
    const double rawFeet = meters * 3.281;

    double feet = 0, inches = 0;
    const float fractionalFoot = modf (rawFeet, &feet);
    inches = fractionalFoot * 12;

    printf ("feet = %f, inches= %.2f\n", feet, inches);

    return 0;
}

This worked for me (Keep in mind I am a greenhorn)

[code]
// Declare function for metersToFeetAndInches
void metersToFeetAndInches(double meters, unsigned int *ftPtr, double *inPtr)
{
// Convert meters into floating point number of feet
double rawFeet = meters * 3.281;
double rawInches;
double wholeFeet;

// Break rawFeet into wholeFeet and rawInches
rawInches = modf(rawFeet, &wholeFeet);


//Store wholeFeet at address ftPtr, and avoid "dereferencing NULL" with if statement
if (ftPtr) {
    printf("Storing %.1f to the address %p\n", wholeFeet, ftPtr);
*ftPtr = wholeFeet;
}

// Turn inches into a usable number
double inches = rawInches * 12.0;
 
// Store inches at inPtr, and avoid "dereferencing NULL" with if statement
if (inPtr) {
    printf("Storing %.2f to the address %p\n", inches, inPtr);
    *inPtr = inches;
}

}

int main(int argc, const char * argv[])
{
// Declare meters and state it’s value
double meters = 3.0;

// Declare feet  // Declare inches
unsigned int feet;
double inches;

// Use the function?
metersToFeetAndInches(meters,&feet, &inches);
printf("%.1f meters is equal to %d feet and %.1f inches.\n", meters, feet, inches);
return 0;

}[/code]