Computing > Programming

Pointer confusion in C -language

(1/37) > >>

Veketti:
Dear All,

https://www.geeksforgeeks.org/convert-floating-point-number-string/

I'm wondering why does pointer "res" work with this syntax. First of all variable "res" is not with * inside the ftoa -function. Then in main function, res is not called with & -prefix.

--- Code: ---// Converts a floating-point/double number to a string.
void ftoa(float n, char* res, int afterpoint)
{
// Extract integer part
int ipart = (int)n;

// Extract floating part
float fpart = n - (float)ipart;

// convert integer part to string
int i = intToStr(ipart, res, 0);

// check for display option after point
if (afterpoint != 0) {
res[i] = '.'; // add dot

// Get the value of fraction part upto given no.
// of points after dot. The third parameter
// is needed to handle cases like 233.007
fpart = fpart * pow(10, afterpoint);

intToStr((int)fpart, res + i + 1, afterpoint);
}
}

// Driver program to test above function
int main()
{
char res[20];
float n = 233.007;
ftoa(n, res, 4);
printf("\"%s\"\n", res);
return 0;
}

--- End code ---

To my understanding this should be:

--- Code: ---// Converts a floating-point/double number to a string.
void ftoa(float n, char *res, int afterpoint)
{
// Extract integer part
int ipart = (int)n;

// Extract floating part
float fpart = n - (float)ipart;

// convert integer part to string
int i = intToStr(ipart, *res, 0);

// check for display option after point
if (afterpoint != 0) {
*res[i] = '.'; // add dot

// Get the value of fraction part upto given no.
// of points after dot. The third parameter
// is needed to handle cases like 233.007
fpart = fpart * pow(10, afterpoint);

intToStr((int)fpart, *res + i + 1, afterpoint);
}
}

// Driver program to test above function
int main()
{
char res[20];
float n = 233.007;
ftoa(n, &res, 4);
printf("\"%s\"\n", res);
return 0;
}

--- End code ---

Are both examples actually the same, but the first is just some simplified version that compiler also understands? Testing in STM32CubeIDE

golden_labels:

--- Quote from: Veketti on June 20, 2021, 01:56:16 pm ---First of all variable "res" is not with * inside the ftoa -function.
--- End quote ---
Because:
--- Code: ---a[b]  == *(a + b)
--- End code ---
Quite literally, including both + and the square brackets operators being commutative.

--- Quote from: Veketti on June 20, 2021, 01:56:16 pm ---Then in main function, res is not called with & -prefix.
--- End quote ---
Because in C arrays ot type T can be implicitly casted to T* pointing to the first element of such array.

More specifically:
In main there is a variable res. That variable is an object consisting of 20 elements of type char.
The ftoa function accepts a pointer to char as its second argument (char*).
Upon invocation, a pointer to the first element of res is taken and passed to that second argument. It is exactly equivalent of:
--- Code: ---char res[20];
char* ptr = &res[0];
ftoa(…, ptr, …);
--- End code ---

This should not be confused with &res, which would have a different type:
--- Code: ---&res[0] // `res[0]` is `char`, `&res[0]` is `char*`
&res // `res` is a `char[20]`, `&res` is `char(*)[20]`
--- End code ---
Due to how compilers are implemented, they may appear numerically equal if inspected and — ignoring compile errors/warnings — using them interchangeably may by pure coincidence seem to “work”. But they are not equal as they have different types. The latter type is also rarely seen in the wild, so don’t worry you don’t the notation now — quite likely you will not see it for the next few years.

Siwastaja:
Yes, as explained above, you can access a pointer like it was an array. Accessing something[0] is the same as *something. Then something[1] will be the next element, i.e., the compiler knows the size of the type and goes forward that many bytes.

You get used to it; it's very common to see
uint8_t single_variable;
uint8_t buffer[1024];
some_function(&single_variable);
some_function(buffer);

In such case, the latter would be equivalent to:
some_function(&buffer[0])

Veketti:
Thank you. One more thing. I noticed if I had in the main funtion the char array with different name eg:

--- Code: ---    char notthesamename[20];
float n = 233.007;
ftoa(n, notthesamename, 4);

--- End code ---
It did still work. Should it, as ftoa -function is still handling char* res?

However if I changed the char array size to 33, it worked for a while and then the MCU started behaving strangely.

Thanks for helping

--- Quote from: Veketti on June 20, 2021, 04:03:21 pm ---It did still work. Should it, as ftoa -function is still handling char* res?

--- End quote ---
Yes, the function is independent of the calling code.

--- Quote from: Veketti on June 20, 2021, 04:03:21 pm ---However if I changed the char array size to 33, it worked for a while and then the MCU started behaving strangely.

--- End quote ---
How strangely? There is nothing inherently wrong with larger array size.

Your code does the work and exits, so I don't see how working "for a while" is even possible.

The only thing to keep in mind that this array is allocated on the stack, and the stack may overflow. But 33 bytes and this simple program should not cause stack overflow issues.