Click to See Complete Forum and Search --> : How do pointer arrays work? in C


azambuja
02-24-2006, 11:58 PM
Ok, so what I learned (which was a while ago; and I don't have a great memory to begin with) is that when you have array of pointers, the **var holds the pointer to the first thing you pointed at, so that var[0] would just return that pointer, and var[1] would return that pointer + a "jump" according to the size of the type of pointer you have, getting you to the second pointer (considering memory is allocated linearly), and var[2] would return pointer+jump+jump, and so on.... visually that's what it would look like:

memory: address1:16bits -> address2: 16bits -> address3: 16bits

so that var[0] would return address1, var[1] would return address1+16bits (=address2), and so on; thus within my little theory the code at the end should work (it segfaults after Done)...

So did I learn/remember/read/write/etc wrong, and I'm 100% out of wack, or am I at least partially right?

Thanks a bunch!!!!!



#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

struct quiters {
int hot;
int cold;
};

int main(){
struct quiters *pump, **pumpers;
pump=(struct quiters *) malloc((sizeof(struct quiters)*2));
pumpers=&pump;

printf("Doing 1:\t");
pumpers[0]->hot=119;
pumpers[0]->cold=19;
printf("Ok\n");
printf("Doing 2:\t");
pumpers[1]->hot=37;
pumpers[1]->cold=88;
printf("Ok\n");
printf("Done\n");

printf("1: hot: %d\tcold:%d\n",pumpers[0]->hot,pumpers[0]->cold);
printf("2: hot: %d\tcold:%d\n",pumpers[1]->hot,pumpers[1]->cold);
return(0);
}

bwkaz
02-25-2006, 09:46 AM
When you assign the address of a variable to a pointer, you cannot go past the first element in the "array" you created. It's only pointing to one other variable, not two, so you can't say pumpers[1]->anything. pumpers[1] doesn't exist. (Well, it does, but it's uninitialized memory, it could point at anything. In your case, it points at memory that you don't own.)

To fix the problem, you would have to allocate a block of memory for the pointers themselves, then another block of memory for each pointer to point to. Your code is creating only a single block of memory large enough to hold two of your structs, but that's being assigned to the wrong variable. It should be:

pumpers = malloc(2 * sizeof(*pumpers));

for(i=0; i<2; i++) {
pumpers[i] = malloc(sizeof(*(pumpers[i])));
}

pumpers[0]->hot = number1;
pumpers[0]->cold = number2;

pumpers[1]->hot = number3;
pumpers[1]->cold = number4; But to go past pumpers[1], you'd have to change both the first malloc and the for loop.

(And addresses are 32 bits, not 16. Unless you're programming in DOS, that is, and no one programs in DOS anymore.)

Here's where you went wrong:

so that var[0] would return address1, var[1] would return address1+16bits No. var[0] would return the address stored at address1, and var[1] would return the address stored at address1+16bits (or 32 on any sane OS). Then the -> indirects through the address that gets returned. The problem is, without explicitly setting pumpers[1] to something, the address stored at address1+16bits is garbage.

azambuja
02-25-2006, 06:28 PM
bwkaz, thanks! Nice to know we can count on our resident guru.

Here's the thing though, it later occured to me that what I wanted is something like the program at the end; still, even though it works, I wanna know if it's misbehaving memory-wise.

Thanks, again.


#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

struct quiters {
int hot;
int cold;
};

int main(){
struct quiters *pump, **pumpers;
pump=(struct quiters *) malloc((sizeof(struct quiters)*2));
// pumpers=&pump;

printf("Doing 1:\t");
pump->hot=119;
pump->cold=19;
printf("Ok\n");
printf("Doing 2:\t");
pump++;
pump->hot=37;
pump->cold=88;
printf("Ok\n");
printf("Done\n");

pump--;
printf("1: hot: %d\tcold:%d\n",pump->hot,pump->cold);
pump++;
printf("2: hot: %d\tcold:%d\n",pump->hot,pump->cold);
return(0);
}

bwkaz
02-26-2006, 03:00 PM
Here's the thing though, it later occured to me that what I wanted is something like the program at the end; still, even though it works, I wanna know if it's misbehaving memory-wise. Not misbehaving, but this isn't the canonical way of doing stuff like this. The canonical way is to:

struct quiters {
int hot;
int cold;
};

int main(){
struct quiters *pump;

pump=malloc(2*sizeof(*pump));

printf("Doing 1:\t");
pump[0].hot=119;
pump[0].cold=19;
printf("Ok\n");

printf("Doing 2:\t");
pump[1].hot=37;
pump[1].cold=88;
printf("Ok\n");

printf("Done\n");

printf("1: hot: %d\tcold:%d\n",pump[0].hot,pump[0].cold);
printf("2: hot: %d\tcold:%d\n",pump[0].hot,pump[0].cold);
return(0);
} This way, it's a bit more obvious that you're handling multiple struct instances in an array.

(Also note two things: (1) In C, you don't have to cast the return value from malloc; if you do, you will suppress the warning that you would otherwise get if you forget to include the proper malloc header. (In C++, you do have to cast it, but in C++, you should be using new instead of malloc.) (2) sizeof(struct quiters) and sizeof(*pump) both have the same value, but the second is safe against all future modifications. If you change the name of the struct, or add a struct quiters_2, or something like that, then if you use sizeof(struct whatever), you have to change both the variable declaration and the malloc call. If you use sizeof(*pump), then you only have to change the declaration, and the compiler will figure out the proper size to use. I also tend to put the number of elements before the sizeof(...), but that's just personal style (I find it easier to tell how many array items are there), it doesn't change the meaning of the program at all.)

azambuja
02-26-2006, 10:09 PM
Ohh ok gotcha
Thanks again bwkaz...

I didn't know about the sizeof(*pumps) thing, and I tried the pump[0] thing before only I used pump[0]-> instead of pump[0]. and it didn't work (doh)... I guess I got some (re-)reading to do.

Thanks