GIDForums  

Go Back   GIDForums > Computer Programming Forums > C Programming Language
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 20-Oct-2006, 13:08
nkhambal nkhambal is offline
Regular Member
 
Join Date: Jul 2004
Location: CA USA
Posts: 313
nkhambal is a jewel in the roughnkhambal is a jewel in the rough

Need help with pointer to pointer


Hello Folks,

I have been out of touch with C for a while now. Forgettin some basics. Following code is a simulator of the part of the large code that I am planning to implement. Basically here what it is, i have array of pointer stored in a structure. I do not know as to how many pointers I will hold this array in the begining. As the code progress I go on adding pointer to the array. I keep a count of how many pointers I added to the array in the structure itself by incrementing it everytime I add a pointer to the array.
Now this is what I am doing (or atleast tryin) in the following code. It's working, but I am not sure if what I am seeing is correct. Can some one help me understand it.

CPP / C++ / C Code:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

int main()
{
    int **p = NULL;
    int **top = NULL;
    char line[50];
    int arr[10];
    int i,idx;

    idx = 0;

    while (1)
    {
        printf("Enter a number to store. -1 to end: ");
        fgets(line,sizeof(line),stdin);
        sscanf(line,"%d", &i);

        if (i == -1)
          break;
        else
          arr[idx] = i;

        if (p == NULL)
        {
            p = (int **)malloc(sizeof(int *));
            (*p) = (int *)malloc(sizeof(int));

            assert (p != NULL && (*p) != NULL);
            printf("p = %p (*p) = %p\n",p,(*p));
            (*p) = &arr[idx];
            idx++;
            top = p;
        } else {
            p++;
            p = (int **)malloc(sizeof(int *));
            (*p) = (int *)malloc(sizeof(int));

            assert (p != NULL && (*p) != NULL);
            printf("p' = %p (*p)' = %p\n",p,(*p));
            (*p) = &arr[idx];

            idx++;
        }
    }

    printf("Entered %d elements\n",idx);

    for (i=0;i< idx; i++)
    {
        printf("p'' = %p   (*p)'' = %p  arr[%d]: %d\n", top, (*top),i,*(*top));
        top = top+ (sizeof(int **) + sizeof(int *));
    }

    return 0;
}


Following is the sample output. My question is why the values of (*p)'' are different than what we are seeing in (*p) and (*p)'.

Quote:
Enter a number to store. -1 to end: 1
p = 0x8049958 (*p) = 0x8049968
Enter a number to store. -1 to end: 2
p' = 0x8049978 (*p)' = 0x8049988
Enter a number to store. -1 to end: 3
p' = 0x8049998 (*p)' = 0x80499a8
Enter a number to store. -1 to end: 4
p' = 0x80499b8 (*p)' = 0x80499c8
Enter a number to store. -1 to end: 5
p' = 0x80499d8 (*p)' = 0x80499e8
Enter a number to store. -1 to end: -1
Entered 5 elements
p'' = 0x8049958 (*p)'' = 0xbfffe7b0 arr[0]: 1
p'' = 0x8049978 (*p)'' = 0xbfffe7b4 arr[1]: 2
p'' = 0x8049998 (*p)'' = 0xbfffe7b8 arr[2]: 3
p'' = 0x80499b8 (*p)'' = 0xbfffe7bc arr[3]: 4
p'' = 0x80499d8 (*p)'' = 0xbfffe7c0 arr[4]: 5

BTW, this is anintel PC running Linux and my compiler is gcc.

Thanks,
  #2  
Old 20-Oct-2006, 17:37
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 4,703
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: Need help with pointer to pointer


Quote:
Originally Posted by nkhambal

Following is the sample output. My question is why the values of (*p)'' are different than what we are seeing in (*p) and (*p)'.

You have assigned the address of the array elements to values of (*p) (after you printed out the values that malloc() gave you).

Put this before the while() loop:
CPP / C++ / C Code:
    for (i = 0; i < 5; i++) {
        printf("&arr[%d] = %p\n", i, &arr[i]);
    }

These are what you see at the end.

Now, that that's out of the way, I have to say that everything that I can think of that could be wrong with this program is wrong. (And I mean really wrong.)

You have a loop that calls malloc() for sizeof(int *) and sizeof (int). Now it just turns out (according to your printout) that each time through the loop the address of the next thing that malloc() gives you is 32 bytes greater that the previous time through the loop. Please note that this is just "happenstance", and is not in any way defined by the language standard. Why 32 bytes? It's implementation-dependent.

You save the very first address in a variable, top, that is an (int **), and later in the program you start at that address and increment it by (sizeof(int **) +sizeof(int *). Now if the size of a pointer is 4 bytes and you add one to it, then you have actually added four to its value. If you increment a pointer by 4 + 4 you are actually adding 32 to the byte count. So, in this particular case you end up pointing to the next thing that was allocated. This is really horrible, and I can't tell you how sorry I am that it "just happened" to appear to be giving you something familiar in your printout. It is wrong, wrong, wrong. (And I mean really wrong.)

1. There is absolutely no guarantee that successive calls to malloc() will give any kind of sequential addresses.

2. It just happens that in this case malloc() gives blocks of 16 bytes for each call with sizeof(int *) and sizeof(int). (So each time through the loop gets a value that is 32 bytes more than the previous time through the loop.)

Note that on some systems (64-bit Linux with gcc, for example), sizeof(int *) is 8 and sizeof (int) is 4. I have no idea (and have absolutely no interest in finding out) what the actual boundaries of successive blocks from malloc() happen to fall on. It doesn't really matter, since it is undefined behavior. Anything that depends on sizeof(int *) and sizeof(int) being somehow related is doomed, doomed, doomed.

3. When you get something from malloc(), you are allowed to access the specific area defined by the argument you gave to malloc(), and other stuff is strictly off-limits.

4. I am just too tired to go on....


In C, if you want to have an array (of anything) but you don't know how big it is eventually going to be, then you might think of doing something else (maybe a linked list or some such thing).

On the other hand, there are plenty of applications that really need it to be an array (where an array is defined to be something that occupies a contiguous memory). The function malloc() for any given call, will give you a block of contiguous memory, and that's why it's so useful for making dynamic arrays.

However, and I hate to repeat myself, but: successive calls to malloc() will not necessarily give you contiguous memory blocks.

In C one way to do it is to use malloc() to get a specific size block of memory for your array. If your needs grow beyond the original block, then you can use realloc() to make the array grow. This is the kind of thing that is taken care automatically by certain C++ classes (like strings and vectors, and stuff like that).

Regards,

Dave
  #3  
Old 20-Oct-2006, 19:39
nkhambal nkhambal is offline
Regular Member
 
Join Date: Jul 2004
Location: CA USA
Posts: 313
nkhambal is a jewel in the roughnkhambal is a jewel in the rough

Re: Need help with pointer to pointer


Hi Dave,

thanks for you response.

How about this.?

I think this is what I was intending to do.

Code:
#include <stdio.h> #include <stdlib.h> #include <assert.h> int main() { int **p = NULL; char line[50]; int arr[220]; int i,idx; idx = 0; while (1) { printf("Enter a number to store. -1 to end: "); fgets(line,sizeof(line),stdin); sscanf(line,"%d", &i); if (i == -1) break; else arr[idx] = i; if (p == NULL) { p = (int **)malloc(sizeof(int *)); (*p) = &arr[idx]; assert (p != NULL && (*p) != NULL); printf("p = %p (*p) = %p\n",p,(*p)); idx++; } else { p = (int **)realloc(p,sizeof(int *)); p[idx] = &arr[idx]; assert (&p[idx] != NULL && p[idx] != NULL); printf("p' = %p (*p)' = %p\n",(p+idx),*(p+idx)); idx++; } } printf("Entered %d elements\n",idx); for (i=0;i< idx; i++) { printf("p'' = %p (*p)'' = %p arr[%d]: %d\n", (p+i), *(p+i),i,*(*(p+i))); } return 0; }

I see some problem with the printf() output, 4th element I add to the array is not displayed correcty. Pointer offsets by one byte memory location. Is this a printf() related problem?

sample Output
Quote:
Enter a number to store. -1 to end: 1
p = 0x80499d8 (*p) = 0xbfffe670
Enter a number to store. -1 to end: 2
p' = 0x80499dc (*p)' = 0xbfffe674
Enter a number to store. -1 to end: 3
p' = 0x80499e0 (*p)' = 0xbfffe678
Enter a number to store. -1 to end: 4
p' = 0x80499e4 (*p)' = 0xbfffe67c <-----
Enter a number to store. -1 to end: 5
p' = 0x80499e8 (*p)' = 0xbfffe680
Enter a number to store. -1 to end: -1
Entered 5 elements
p'' = 0x80499d8 (*p)'' = 0xbfffe670 arr[0]: 1
p'' = 0x80499dc (*p)'' = 0xbfffe674 arr[1]: 2
p'' = 0x80499e0 (*p)'' = 0xbfffe678 arr[2]: 3
p'' = 0x80499e4 (*p)'' = 0xbfffe67d arr[3]: 83886080 <------
p'' = 0x80499e8 (*p)'' = 0xbfffe680 arr[4]: 5

Thanks for your help
  #4  
Old 20-Oct-2006, 20:03
nkhambal nkhambal is offline
Regular Member
 
Join Date: Jul 2004
Location: CA USA
Posts: 313
nkhambal is a jewel in the roughnkhambal is a jewel in the rough

Re: Need help with pointer to pointer


Hi Dave,

Never mind. Changing the following statement,

CPP / C++ / C Code:
p = (int **)realloc(p,sizeof(int *));

to

CPP / C++ / C Code:
p = (int **)realloc(p,(sizeof(int *) * (idx+1)));

fixed the problem.

Quote:
Enter a number to store. -1 to end: 1
p = 0x80499f8 (*p) = 0xbffff0f0
Enter a number to store. -1 to end: 2
p' = 0x80499fc (*p)' = 0xbffff0f4
Enter a number to store. -1 to end: 3
p' = 0x8049a00 (*p)' = 0xbffff0f8
Enter a number to store. -1 to end: 4
p' = 0x8049a04 (*p)' = 0xbffff0fc
Enter a number to store. -1 to end: 5
p' = 0x8049a08 (*p)' = 0xbffff100
Enter a number to store. -1 to end: -1
Entered 5 elements
p'' = 0x80499f8 (*p)'' = 0xbffff0f0 arr[0]: 1
p'' = 0x80499fc (*p)'' = 0xbffff0f4 arr[1]: 2
p'' = 0x8049a00 (*p)'' = 0xbffff0f8 arr[2]: 3
p'' = 0x8049a04 (*p)'' = 0xbffff0fc arr[3]: 4
p'' = 0x8049a08 (*p)'' = 0xbffff100 arr[4]: 5
  #5  
Old 20-Oct-2006, 21:06
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 4,703
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: Need help with pointer to pointer


Quote:
Originally Posted by nkhambal
Hi Dave,

Never mind. Changing the following statement,

CPP / C++ / C Code:
p = (int **)realloc(p,sizeof(int *));

to

CPP / C++ / C Code:
p = (int **)realloc(p,(sizeof(int *) * (idx+1)));

fixed the problem.


OK! That's the idea.

Now, if you are going to get serious about this, there are a couple of points that you might consider:

First, using realloc for each and every new item is very inefficient. I think the usual thing is to allocate a sizeable chunk of memory and when its limit is reached, then realloc to get some more.

Then, I think you should always test the return values of malloc() and realloc(), since it is possible that memory is exhausted or, maybe, fragmented in such a way that no further allocation is possible. After all, the only way that you could justify the complexity of using realloc is for programs whose data requirements could be very large (otherwise just used fixed arrays, right?).

Now with large, sophisticated programs, if realloc fails, the program might take some corrective action by writing some of its data base onto a disk file and freeing its memory, then, maybe reading it back in as needed into some contiguous memory. The point is that if realloc fails, then the way you have written it, all is lost, since you wipe out the previous value of the pointer.

I would suggest something like the following:

CPP / C++ / C Code:
    int **temp;

.
.
.
            temp = (int **)realloc(p,sizeof(int *)*(idx+1));
            if (temp == NULL) {
                printf("error allocating %d pointers to int\n", idx+1);
             /* 
              * do something here to recover some memory  before
              * continuing
              */
            }
            p = temp;

Of course if all you are going to do is exit(), then there is value in worrying about saving the value of the pointer, since all is lost.

However if you do something like my example above, you may be able to figure out some way to continue, since the original value of p is intact.

Let us know how it goes.

Regards,

Dave
  #6  
Old 21-Oct-2006, 04:13
nkhambal nkhambal is offline
Regular Member
 
Join Date: Jul 2004
Location: CA USA
Posts: 313
nkhambal is a jewel in the roughnkhambal is a jewel in the rough

Re: Need help with pointer to pointer


Thanks Dave, i will your inputs in mind while coding.

Thanks again for your help.

Regards,
 
 

Recent GIDBlogMeeting the populace by crystalattice

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
2D arrays:dynamic allocation and freeing bravetanveer C Programming Language 48 27-Nov-2007 15:55
Pointer Usage in C++: Beginner to Advanced varunhome C++ Forum 0 19-Aug-2005 09:25
[Tutorial] Pointers in C (Part II) Stack Overflow C Programming Language 0 27-Apr-2005 17:36
[Tutorial] Pointers in C (Part I) Stack Overflow C Programming Language 1 08-Apr-2005 18:35

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 21:05.


vBulletin, Copyright © 2000 - 2008, Jelsoft Enterprises Ltd.