0

I'm new to C, and I'm writing a very basic function that takes an integer pointer as a parameter. Inside the function, a float pointer must be created. This function must assign the value of the integer pointer to the float and then return the float. Here's my code at the moment:

float * function(const int *x)
{
    float *p = (float*)x;
    return p;
}

But this results in an error that reads as such when run: "free(): invalid pointer: 0x00007fffc0e6b734". Suffice it to say, I'm very confused. Any insights you can offer would be much appreciated!

user3246779
  • 125
  • 3
  • 12
  • 1
    Post the the relevant code, this rather useless function is not the problem. – this Jan 28 '14 at 23:58
  • 4
    *a float pointer must be created* -- Why? *This function must assign the value of the integer pointer to the float and then return the float* -- "float" and "float pointer" are very different things. Be precise about what you mean, which at this point is impossible to determine. – Jim Balter Jan 29 '14 at 00:00
  • btw, your function assumes that internally both `float` and `int` are saved the same way.. have the same representation internally, but thats not the case. If you want to convert `int` to `float`, try one of the math functions like `round` or `floor`. And as mentioned before, the problem you describe is happening in another place. – wendelbsilva Jan 29 '14 at 00:02
  • @wendelbsilva The function does not assume that. Such an assumption may occur elsewhere, but not in the posted code. – Jim Balter Jan 29 '14 at 00:05
  • See [Pointers in C: when to use the ampersand and the asterisk](https://stackoverflow.com/questions/2094666/pointers-in-c-when-to-use-the-ampersand-and-the-asterisk) – JB0x2D1 Jan 29 '14 at 00:07
  • @JimBalter What do you mean? The way I see the 4 bytes of the integer will be assigned to the float but, since their internal representation are different, they will have different value. Am I missing something? – wendelbsilva Jan 29 '14 at 00:08
  • @wendelbsilva Yes, you're missing everything. No integers or floats are being assigned in that function, only pointers, and those pointers are guaranteed to be the same size by the C Standard. – Jim Balter Jan 29 '14 at 00:12
  • @JimBalter Yes, I do agree they will point to the same position and have the same size. I was thinking about later, if they plan to read the value in that position. – wendelbsilva Jan 29 '14 at 00:13
  • *I was thinking about later, if they plan to read the value in that position* -- that's what I said. Your "What do you mean" is inexplicable. Anyway, Reading the value isn't necessarily an error ... a float may have been stored through the `int*` for some reason. – Jim Balter Jan 29 '14 at 00:16
  • Most likely, you're either freeing the data twice (maybe once for the `int *` and once for the `float *`), or the data wasn't dynamically allocated in the first place. You need one `free()` per dynamic allocation, not one `free()` per pointer. – Dmitri Jan 29 '14 at 00:26
  • In the function you need to 1. allocate memory `malloc` for a `float` type value, 2. asign the data pointed to `*p = *x`, 3. return the ponter. Now you are just making the memory locations same. – ssm Jan 29 '14 at 00:56
  • @JimBalter: Where does the C standard guarantee that `int *` and `float *` have the same size? – Eric Postpischil Jan 29 '14 at 01:09
  • @EricPostpischil Where it's permeated with my brainfart. I shoulda read http://stackoverflow.com/questions/916051/are-there-are-any-platforms-where-pointers-to-different-types-have-different-siz – Jim Balter Jan 29 '14 at 01:16
  • Before you head off into that good night thinking a pointer-to-float cast from a pointer-to-int will give you the floating point value of said original `int` on dereference, I strongly suggest you [read this first](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html), as well as Annex F of the C9899 standard. It won't work that way you think it will. – WhozCraig Jan 29 '14 at 02:01

2 Answers2

0

Being new to C, are you familiar with the scope of variables? (Part of) the short version of variable scope is that if you don't do a little something extra, a variable created in a function only exists inside that function. Why that's important to you: if you return a pointer to a variable that you created inside a function (without doing that little something extra) that pointer will point to an area of memory that may or may not contain the value that you assigned to it. One way to do what you want is this:

float *makefloat(int *x) {

//  static keyword tells C to keep this variable after function exits
    static float f;

//  the next statement working from right to left does the following
//  get value of pointer to int (x) by dereferencing:   *x
//  change that int value to a float with a cast:       (float)
//  assign that value to the static float we created:   f =
    f = (float) *x; 
//  make pointer to float from static variable:         &f
    return &f;
}

In general I seem to see more functions that accept a pointer to the variable that is to be modified, then in that function the new value is created and assigned to the area in memory referenced by the pointer. Because that area of memory exists outside of the scope of the function, there is no need to worry as much about scope and static variables. Another cool thing about static variables is that the next time the function is called, the static variable has the same value it did when the function last exited. Explained on Wikipedia.

Good explanation of * and &: Pointers in C: when to use the ampersand and the asterisk

Community
  • 1
  • 1
JB0x2D1
  • 838
  • 8
  • 20
  • 3
    He's not returning a pointer to a function's local variable, though. He's returning a pointer to data pointed at by a pointer passed as a function argument (as a different pointer type). It's kind of like using a function to perform a type cast. – Dmitri Jan 29 '14 at 01:46
  • @Dmitri Good point +1 – JB0x2D1 Jan 29 '14 at 02:25
0

Your function only performs a pointer conversion. A function call of the form

q = function(p); /* p is a "const int *" pointer,
                    q is assignment comaptible with "float *". */

can be replaced by the expression:

q = (float *) p;

by itself, this doesn't do any harm. The problem is elsewhere in your program.

Note that most type punning, like accessing an object of type int using an expression of type float via pointers, is undefined behavior in the C language. This isn't going on in the example code, but things are headed in that direction; the pointer is probably being prepared for carrying out type punning.

Consider that int and float don't necessarily even have the same size; and that is not the only consideration. In code like this:

int i = 42;
/* now treat i as a float and modify it sneakily */
*((float *) &i) = 3.14;

printf("i = %d\n", i);

the output of the printf can still be 42. The optimizing compiler can put i into a machine register, whereas the sneaky assignment might be performed on the memory location that serves as the "backing storage" for i, and so i appears unchanged since the printf call uses the register-cached copies. The compiler is not required to consider that a modification of an object designated by the type float might affect the value of an object of type i (even if they otherwise have the same size, so there is no collateral damage done by the assignment, like overwriting other objects).

In the real world, sometimes it is necessary to write a code that manipulates floating-point objects as if they were integers: typically unsigned int integers, to gain access to the bitwise representation of the float. When this is done, you have to use unions, or perhaps compiler-specific features, like GCC's -fno-strict-aliasing option which causes the compiler to optimize more cautiously in the face of type punning. in that kind of code, you make sure that the assumptions are all warranted about the sizes of types and such, with #ifdef-s for different platforms, perhaps based on values pulled from running configured scripts to detect platform features.

Needless to say, this is not a good way to be learning C at a beginner level.

Kaz
  • 55,781
  • 9
  • 100
  • 149