PDA

View Full Version : [SOLVED] Changing the value of a pointer in a subroutine




Eraserhead
Nov 27, 2007, 11:21 AM
For my programming assignment this week I have a problem where I need to assign a value to a pointer in a subroutine and it doesn't seem to be reflected in the main part of the code.

int main (int argc, const char * argv[]) {
/* read in data.*/
double *data;
//unsigned long v=0.0;/*So noOfFloatsP has something to initially point to.*/
unsigned long *noOfFloatsP;//=&v;
if(readFloatDataAsDoublesFromFile("prj4data.dat",data,noOfFloatsP)){
printf("Error reading in data, see previous error message for more details. Exitting the program.\n");
return 1;
}
if(noOfFloatsP==NULL){
printf("Error, pointer 'noOfFloatsP' is empty, exiting.\n");
exit(EXIT_FAILURE);
}
unsigned long noOfFloats=(unsigned long)*noOfFloatsP;
printf("noOfFloatsMain=%u\n",noOfFloats);
}

now noOfFloatsMain is still zero, even though in readFloatDataAsDoublesFromFile() sets the value to 1896.

What am I doing wrong?



Gelfin
Nov 27, 2007, 11:51 AM
1. You are initializing "v", an integer value, with "0.0". This probably won't break, but just isn't right. Floats and integers are somewhat less magically interchangeable in C than in Java.

2. You seem to be not quite understanding pointers yet. You've created a number of things in memory where you only need one. From the context it looks as if you are meant to pass a pointer to an unsigned long into the function, and receive the number of items read from the data file. All you need is one unsigned long, noOfFloats, and to pass the address of that value into your function as &noOfFloats.

3. You seem to be not quite understanding pointers yet, part 2: Even if you needed to explicitly declare noOfFloatsP, there is no need to test whether noOfFloatsP is NULL, because you declared and assigned it to a location you know to be valid (the address of something in the current stack frame will always be valid). There is no way the function can modify the value of the pointer, only the value of the data it points to (i.e., noOfFloats).

For all that awkwardness, I'm not seeing anything in this function that should cause your problem, so I must resort to guessing, and my spider-sense is telling me that within "readFloatData..." you are assigning the number of floats to noOfFloatsP instead of *noOfFloatsP (or whatever you named your third function argument).

Eraserhead
Nov 27, 2007, 01:15 PM
It is assigned in the read function using &numberOfFloats;

The beginning of my "read in" method is the following:

int readFloatDataAsDoublesFromFile(const char * filename, double * array, unsigned long *noOfFloatsP){
struct stat st;/*The file stats.*/
FILE *file;/*< The reference to the file.*/
unsigned long i;/*< For iterations.*/
/*First check if file exists. Taken from http://www.gamedev.net/community/forums/topic.asp?topic_id=266856 if not 0 is returned.*/
if(stat(filename, &st)!=0){
printf("Error input file '%s' doesn't exist.\n",filename);
return 1;
}
unsigned long noOfFloats=(unsigned long)st.st_size/sizeof(float);/*< Help from prj2 wrapper and man stat.*/
noOfFloatsP=&noOfFloats;
printf("noOfFloats=%u\n",*noOfFloatsP);
return 0;


It has been deliberately cut short, so no actual data has been read in. However which the initial code I get the following result from Xcode and my University Unix Server:


noOfFloats=1896
Error, pointer 'noOfFloatsP' is empty, exiting.


I'm pretty sure it worked yesterday so I'm not sure what I've managed to do :confused:.

iSee
Nov 27, 2007, 01:23 PM
The specific problem you (the OP) ask about is in the implementation of readFloatDataAsDoublesFromFile.

Your code is:

noOfFloatsP=&noOfFloats;

But keep in mind that noOfFloatsP is just a pointer to an unsigned long value. When you assign a value directly to it, you are just changing what it points to, not the value of what it points to.

So, you want to do this:

*noOfFloatsP = noOfFloats;

(For those that don't know, the * in this context means, "give me the value of what the following pointer points to.")


Edit: Also, in your main function, you should make sure to initialize noOfFloatsP (What you commented out seems right). You will also need to make sure data is pointing to something before you try to use it like an array. Right now isn't pointing to anything.

Eraserhead
Nov 27, 2007, 01:25 PM
The specific problem you (the OP) ask about is in the implementation of readFloatDataAsDoublesFromFile.

I assign it using the & thing, that is made clear in my second post ;).

AlmostThere
Nov 27, 2007, 01:28 PM
The data pointer will not change value.

If you want to allocate memory to a specific pointer in this manner, you need to pass a reference to the pointer (c++) or a pointer to a pointer.

At the risk of jumping to conclusions, I think you are confusing passing by reference, passing by value and passing pointers.

Passing a pointer to an existing value is passing by reference - i.e. you can change the object within the function. Passing a pointer is simply passing by value. If you actually want to allocate into data you need to pass a pointer to data, i.e. a pointer to a pointer.

[edit] more posts while I was writing this... will review new comments

You are setting the noOfFloatsP to the address of a local variable, so it will not point anywhere meaningful when you function finishes.

You want to pass a pointer to the a variable in main to your function and then call *noOfFloatsP = noOfFloats.

[edit] Example

#include <iostream>

void foo(long *pLong)
{
long l = 999;
*pLong = l;
}

int main()
{
long l = 111;
std::cout << l << std::endl;
foo(&l);
std::cout << l << std::endl;
}


[edit]Example of allocating to a specific pointer

#include <iostream>

void allocate(double **d)
{
*d = new double;
**d = 10.01;
std::cout << d << std::endl;
}

int main()
{
double *d = NULL;
allocate(&d);
std::cout << *d << std::endl;
delete d;
}

Eraserhead
Nov 27, 2007, 01:45 PM
OK I'm now malloc'ing the pointer in main, and then using *noOfFloats to assign it and everything seems to be working perfectly! Thanks Guys :).

iSee
Nov 27, 2007, 02:00 PM
I assign it using the & thing, that is made clear in my second post ;).

You need to use the * thing on noOfFloatsP, not the & thing on noOfFloats. :eek:

Hrm... I wish I had time to explain exactly why, because it is critical to properly understanding pointers. Lemmie just try really quickly, but if this makes no sense, definitely review your textbook and/or notes, because this is important if you want to understand pointers at all.

There are some issues of variable scope here, as well.

noOfFloatsP in main() is a pointer.
It points to the value v (once you uncomment the initialization).

So, to diagram it:

--noOfFLoatsP--> v

I'm trying to indicate that noOfFloatsP IS the pointer in the diagram.
It's value of noOfFloats is the address (that is, the location in memory) of v.

Now, v itself has been initialized with the value 0, so I'll put that in the diagram in parens, after v:

--noOfFLoatsP--> v (0)

You then pass noOfFloatsP into the function (I'll just call it "read()" for short).
The noOfFloats in read() isn't actually the same pointer, but it is a copy, so it points to the same location. So you have:

---main's noOfFloatsP------> v (0)
---read's noOfFloatsP----/ (also pointing to v)

So, at the top of read, main's noOfFloatsP and read's noOfFloatsP both point to v, which has the value of zero.

You introduce another variable in read() called noOfFloats. Then you assign a value to it. Let's suppose the value is 1896. So are diagram, just before the assignment to read's noOfFloatsP is:

---main's noOfFloatsP------> v (0)
---read's noOfFloatsP----/
noOfFloats (1896)

Your assignment (noOfFloatsP=&noOfFloats) sets the value of read's noOfFloatsP to the address of noOfFloats. That is, you make read's noOfFloatsP point to reads noOfFloats. The diagram becomes:

---main's noOfFloatsP------> v (0)
---read's noOfFloatsP------> read's noOfFloats (1896)

Now, once you return from read(), read's variables go away, and we are left with:

---main's noOfFloatsP------> v (0)

main's noOfFloatsP still pointing to v, which still has the value of zero: not what you wanted.

Backing up to the assignment in read(), If you use my assignment (*noOfFloatsP = noOfFloats), you are copying the value of noOfFloats to the value that noOfFloatsP points to. So the transition in the diagram from before my assignment to after is:

---main's noOfFloatsP------> v (0)
---read's noOfFloatsP----/
noOfFloats (1896)

*noOfFloatsP = noOfFloats

---main's noOfFloatsP------> v (1896)
---read's noOfFloatsP----/
noOfFloats (1896)

Now, when read() returns and its variables go away, we are left with:

---main's noOfFloatsP------> v (1896)

Which is what you wanted.

Make sense?

Eraserhead
Nov 27, 2007, 02:05 PM
<<Massively Detailed Post>>
Make sense?

Thanks for that, that's a brilliant explanation.