Thread: pointers to pointers in struct

  1. #1
    Registered User
    Join Date
    Mar 2008
    Posts
    17

    pointers to pointers in struct

    hey,

    getting a bit confused with pointers, structs and pointers within structs. I'm trying to use gethostbyname to get resolve a hostname to an ip, which I will then store in the host struct. However, I'm doing something wrong before I even get to the stage of IP's; with copying the hostname.

    I think hp->h_name is a pointer, which is being copied (as a pointer) into h->name. which is why when I call gethostbyname the second time (because it's using the same piece of memory) the 'facebook.com' name is being overwritten.

    the problem I have is that I don't really understand if this is a pointer to a pointer (within the hostent struct), and how I actually assign the contents of h_name to h->name.

    am I correct in thinking, as it stands, h->name now contains a pointer to the memory location used by gethostbyname ? if so, how do I print the memory address contained within h->name ?

    thanks,


    Code:
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #define MAXHOSTS 5
    
    struct host {
        char *name;
        in_addr ip;
    };
    
    struct host hostlist[MAXHOSTS];
    
    int main(int argc, char *argv[])
    {
    
        struct hostent *hp;
    
        hp = gethostbyname("facebook.com");
        hostlist[0].name = hp->h_name;
        printf("hp->h_name %s is at %p, hostlist[0] %s is at %p\n", 
            hp->h_name, &hp->h_name,
            hostlist[0].name, hostlist[0].name);
    
        hp = gethostbyname("google.com");
        hostlist[1].name = hp->h_name;
        printf("hp->h_name %s is at %p, hostlist[1] %s is at %p\n",
            hp->h_name, &hp->h_name,
            hostlist[1].name, &hostlist[1].name);
    
        struct host *p;
    
        int i;
        for (i = 0; i <= MAXHOSTS;) {
            p = &hostlist[i];
    
            printf("%d : (%p) host : (%p) name = %s\n", i, p, p->name, p->name);
            ++i;
        }
        return 0;
    }

  2. #2
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Check your man pages:
    Quote Originally Posted by man gethostbyname
    DESCRIPTION
    The gethostbyname*() and gethostbyaddr*() functions are obsolete. Applications should use getaddrinfo(3) and getnameinfo(3) instead.
    ...
    RETURN VALUE
    The gethostbyname() and gethostbyaddr() functions return the hostent structure or a NULL pointer if an error occurs. On error, the h_errno variable holds an error number.
    When non-NULL, the return value may point at static data, see the notes below.
    ...
    NOTES
    The functions gethostbyname() and gethostbyaddr() may return pointers to static data, which may be overwritten by later calls. Copying the struct hostent does not suf-
    fice, since it contains pointers; a deep copy is required.


    You should switch to getaddrinfo, which is more current. Also, if you printed out the address in hp (i.e. add a "%p" specifier, and pass it just plain old hp), you would see that after both calls to gethostbyname(), you end up with the same hostent structure (same address). Looks like your implementation returns a pointer to static data, as the man pages warns, so you need to use strdup or a malloc/strcpy (remember +1 for the nul) to copy the contents of the name field. This problem is hard for you to detect since you use two different diagnostic print statements:
    Code:
        printf("hp->h_name %s is at %p, hostlist[0] %s is at %p\n", 
            hp->h_name, &hp->h_name,
            hostlist[0].name, hostlist[0].name);
    ...
        printf("hp->h_name %s is at %p, hostlist[1] %s is at %p\n",
            hp->h_name, &hp->h_name,
            hostlist[1].name, &hostlist[1].name);
    That extra ampersand probably confused you.

  3. #3
    Registered User
    Join Date
    Mar 2008
    Posts
    17
    Hi,

    thanks. yeah that extra ampersand was just left there while playing around with the first statement trying different options to print the address in hostlist[0].name.

    I get that gethostbyname uses static memory to save its results. however, I am not understanding why :

    Code:
    hostlist[0].name = hp->h_name;
    doesn't work, and why when I come to print out hostlist[0].name it's printing out what's in hostlist[1].name. I suspect that both of these 'names' (via my assingment) are simply holding the address of the static memory used by gethostbyname, but I don't really understand 'why'.

    cheers

  4. #4
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Static variables, declared in functions, retain their values when they return. You aren't copying the values any place, you are simply pointing both pointers to the same spot in memory. You are in effect doing this:
    Code:
    int x;
    int *p1, *p2;
    
    p1 = &x;
    x = 5;
    p2 = &x;
    x = 6;
    printf( "x is %d\n", *p1 );
    If you want to keep two distinct values of x, stop pointing both pointers at x, and copy the value of x some place.


    Quzah.
    Hope is the first step on the road to disappointment.

  5. #5
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by dougieb View Post
    the problem I have is that I don't really understand if this is a pointer to a pointer (within the hostent struct), and how I actually assign the contents of h_name to h->name.
    If you are working with an array of structs, you probably should not use pointers inside the structs and especially you should not simply copy pointers around...

    Try it like this...

    Code:
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #define MAXHOSTS 5
    
    struct host {
        char name[128];
        in_addr ip;
    };
    
    struct host hostlist[MAXHOSTS];
    
    int main(int argc, char *argv[])
    {
    
        struct hostent *hp;
    
        hp = gethostbyname("facebook.com");
        strcpy(hostlist[0].name, hp->h_name);
        printf("hp->h_name %s is at %p, hostlist[0] %s is at %p\n", 
            hp->h_name, &hp->h_name,
            hostlist[0].name, hostlist[0].name);
    
        hp = gethostbyname("google.com");
        strcpy(hostlist[1].name, hp->h_name);
         printf("hp->h_name %s is at %p, hostlist[1] %s is at %p\n",
            hp->h_name, &hp->h_name,
            hostlist[1].name, &hostlist[1].name);
    
        struct host *p;
    
        int i;
        for (i = 0; i <= MAXHOSTS;) {
            p = &hostlist[i];
    
            printf("%d : (%p) host : (%p) name = %s\n", i, p, p->name, p->name);
            ++i;
        }
        return 0;
    }
    This way the data is stored in the struct as individual strings for each element in the array... much simpler, far easier to manage.

  6. #6
    Registered User
    Join Date
    Mar 2008
    Posts
    17
    hmm.. "especially you should not simply copy pointers around... " is that what 'hostlist[0].name = hp->name' is doing ? is that copying the pointer in hp->name, rather than (as I wanted) copying the contents ? I'm just trying to understand it, so I don't repeat the mistakes.

    so, first output is the original. second is with Tatter's changes. certainly works :-)

    Code:
    $ ./test 
    hp->h_name facebook.com is at 0x9e6da4, hostlist[0] facebook.com is at 0x848a0f5
    hp->h_name google.com is at 0x9e6da4, hostlist[1] google.com is at 0x848a0ff
    0 : (0x8049800) host : (0x848a0f5) name = oogle.com
    1 : (0x8049808) host : (0x848a0ff) name = google.com
    2 : (0x8049810) host : ((nil)) name = (null)
    3 : (0x8049818) host : ((nil)) name = (null)
    4 : (0x8049820) host : ((nil)) name = (null)
    5 : (0x8049828) host : ((nil)) name = (null)
    $ gcc -Wall -o test test.c
    $ ./test 
    hp->h_name facebook.com is at 0x9e6da4, hostlist[0] facebook.com is at 0x8049860
    hp->h_name google.com is at 0x9e6da4, hostlist[1] google.com is at 0x80498e4
    0 : (0x8049860) host : (0x8049860) name = facebook.com
    1 : (0x80498e4) host : (0x80498e4) name = google.com
    2 : (0x8049968) host : (0x8049968) name = 
    3 : (0x80499ec) host : (0x80499ec) name = 
    4 : (0x8049a70) host : (0x8049a70) name = 
    5 : (0x8049af4) host : (0x8049af4) name =

  7. #7
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Yes, you were simply copying the pointer, not the contents, so both [0] and [1] pointed to the same array in static memory, as Quzah pointed out. Tater's solution is a good one (certainly easiest to implement). My only suggestion might be to make the name field bigger (say, 256) since I think that's what the RFC specifies for host names, though I'm not sure so you should double check.

  8. #8
    Registered User
    Join Date
    May 2011
    Location
    Around 8.3 light-minutes from the Sun
    Posts
    1,949
    Sounds to me like you may want to brush up on pointers. Here is one of the better tutorials I have found.
    Quote Originally Posted by anduril462 View Post
    Now, please, for the love of all things good and holy, think about what you're doing! Don't just run around willy-nilly, coding like a drunk two-year-old....
    Quote Originally Posted by quzah View Post
    ..... Just don't be surprised when I say you aren't using standard C anymore, and as such,are off in your own little universe that I will completely disregard.
    Warning: Some or all of my posted code may be non-standard and as such should not be used and in no case looked at.

  9. #9
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by anduril462 View Post
    Yes, you were simply copying the pointer, not the contents, so both [0] and [1] pointed to the same array in static memory, as Quzah pointed out. Tater's solution is a good one (certainly easiest to implement). My only suggestion might be to make the name field bigger (say, 256) since I think that's what the RFC specifies for host names, though I'm not sure so you should double check.
    I would have to look but I believe there's a #define in winsock2.h for the host size...

  10. #10
    Registered User
    Join Date
    Mar 2008
    Posts
    17
    good tutorial Andrew. Although it makes sense, I'd never really considered that 'a pointer' is just variable that has it's own address as well. so &ptr is giving you a pointer to a pointer (assuming ptr has a value).

    also I think (with a combination of what you guys have said and that tutorial) my problem was that

    Code:
    hostlist[0].name = "myspace.com"
    worked, but

    Code:
    hostlist[0].name = hp->h_name
    didn't. BUT, the "myspace.com" string constant, which is just a char array with a beginning address/pointer. but, memory is allocated as it's initialized. so, these two lines are effectively doing the same thing, copying a pointer. it's just that (now obvious, and as was said in the first reply) the string constant is not overwritten so hostlist[0].name can point to it as long as it exists without it being overwritten; unlike the static memory location of gethostbyname. but, crucially, for my understanding, both of the above assignments are doing the same thing, assigning pointers. and the strcpy is used to copy the contents out to a new memory location, and then it is copying the address of that new memory location into hostlist[i].name

    thanks for all your help. I'll keep practicing :-)

  11. #11
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by dougieb View Post
    also I think (with a combination of what you guys have said and that tutorial) my problem was that

    Code:
    hostlist[0].name = "myspace.com"
    worked, but

    Code:
    hostlist[0].name = hp->h_name
    didn't. BUT, the "myspace.com" string constant, which is just a char array with a beginning address/pointer. but, memory is allocated as it's initialized. so, these two lines are effectively doing the same thing, copying a pointer. it's just that (now obvious, and as was said in the first reply) the string constant is not overwritten so hostlist[0].name can point to it as long as it exists without it being overwritten; unlike the static memory location of gethostbyname. but, crucially, for my understanding, both of the above assignments are doing the same thing, assigning pointers. and the strcpy is used to copy the contents out to a new memory location, and then it is copying the address of that new memory location into hostlist[i].name

    thanks for all your help. I'll keep practicing :-)
    Ok, here's a little code sample I post from time to time to illustrate why you should not try to return arrays from functions... or in your case assign pointers to static arrays... Give this a run, I'll bet it explains your problem for you...

    Code:
    #include <stdio.h>
    
    int* MyFunction(int a, int b, int c)
      {  static int array[3];
         array[0] = a;
         array[1] = b;
         array[2] = c;
         return array;  } // return a pointer.
    
    
    int main (void)
      { int *a1, *a2;  // int pointers
    
        printf("calling a1 = MyFunction(10,20,30);\t");
        a1 = MyFunction(10,20,30);
        printf("a1 has %d %d %d\n",a1[0],a1[1],a1[2]);
    
        printf("calling a2 = MyFunction(100,200,300);\t");
        a2 = MyFunction(100,200,300);
        printf("a2 has %d %d %d\n",a2[0],a2[1],a2[2]);
    
        printf("\nLooks good, except...\t"); 
        printf("a1 now has %d %d %d\n",a1[0],a1[1],a1[2]);
    
        getchar();
        return 0; }

  12. #12
    Registered User
    Join Date
    Mar 2008
    Posts
    17
    yep, that's it. makes sense when you understand it :-)

    thanks again..

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. size of struct with pointers and function pointers
    By sdsjohnny in forum C Programming
    Replies: 3
    Last Post: 07-02-2010, 05:19 AM
  2. Want help using struct pointers
    By burkoJames in forum C Programming
    Replies: 2
    Last Post: 05-13-2010, 10:59 PM
  3. Struct as pointers
    By wirefree101 in forum C Programming
    Replies: 8
    Last Post: 12-03-2009, 02:48 PM
  4. pointers to struct - help please
    By seminolas in forum C Programming
    Replies: 2
    Last Post: 12-22-2008, 01:03 AM
  5. Assigning pointers from pointers in struct.
    By Brian in forum C Programming
    Replies: 2
    Last Post: 10-18-2003, 04:30 AM