Following a tutorial, I built a small sample program that uses winsock. It compiles, but there are a few different places I'm not sure what's happening with the pointers. Full source is available here

Line 25:
struct hostent *host;

As near as I can tell, this creates a pointer to a memory address holding an instance of the "hostent" struct and refers to it as "host." What I can't figure out is why
hostent *host;
or

hostent h;
host = *h;

wouldn't accomplish the same thing, as hostent is already an existing struct in the winsock2 header.

Line 37:
socket_address.sin_addr.s_addr = *((unsigned long*)host->h_addr);

The right side, I find utterly baffling. For the "*" inside the parenthesis and to the right of "unsigned long" I can't figure out the significance. As for the one directly to the left of the parentheses, does this just mean the right side provides a pointer to a memory address holding an unsigned long int?

Line 40:
if(connect(server_socket,(SOCKADDR*)(&socket_address), sizeof(socket_address)) != 0)

The second argument the connect function expects is, according to msn's documentation, "[a] pointer to the sockaddr structure to which the connection should be established." As such, it stands to reason that the second argument provided here takes the "SOCKADDR_IN" instance "socket_address" and provides a pointer to it. What I can't understand is the reasoning behind why this syntax does that, and even trying to explain what little I thought I had figured out confused me to the point that whatever logical progress I thought I had made on the matter ceased to make any sense to me.

Thanks in advance.

Recommended Answers

All 3 Replies

struct hostent *host;

As near as I can tell, this creates a pointer to a memory address holding an instance of the "hostent" struct and refers to it as "host."

Not quite. It creates a pointer, named host, pointing at some random piece of memory somewhere. No hostent object has been created.

hostent *host; does the exact same thing. In C, you have to put struct in front of every struct type. In C++, you don't. The first bit of code is C style.

hostent h; creates an actual hostent object, named h. It has not created any pointers.

host = *h; This is an attempt to set host to the same value as what the pointer named h (so far there is no such pointer) is pointing at; it doesn't make much sense here. Perhaps you meant host = &h;

This code makes sense:

hostent *host; // create pointer, currently pointing at random memory.
hostent h; // create a hostent object, named h
host = &h; // make the pointer point at the hostent object I just made

This:
socket_address.sin_addr.s_addr = *((unsigned long*)host->h_addr)
Start small.
host->h_addr get the object named h_addr inside whatever host is pointing at.

(unsigned long*)host->h_addr) Recast that object as a pointer to an unsigned long (i.e. pretend it's a pointer to an unsigned long)

*((unsigned long*)host->h_addr); and derefernce it (i.e. get the unsigned long it is pointing at)

So, all together, this socket_address.sin_addr.s_addr = *((unsigned long*)host->h_addr) means get the h_addr object inside the struct that host is pointing to, and pretend that it's a pointer to an unsigned long, then get that unsigned long value, and then set socket_address.sin_addr.s_addr to that unsigned long value.

For the "*" inside the parenthesis and to the right of "unsigned long"

Pointer. Like int* is a pointer to an int, and unsigned int* is a pointer to an unsigned int, unsigned long*is a pointer to an unsigned long.

This: (unsigned long*) is a cast. It is an instruction to treat whatever follws as an object of typeunsigned long*

(SOCKADDR*)(&socket_address)
This means: get the address of the object named socket_address, so now you've got a pointer to socket_address, and then treat that pointer as if it were a SOCKADDR pointer.

Thanks, that clears up a lot.

One follow-up:
(unsigned long*)host->h_addr
and
(SOCKADDR*)(&socket_address)
are doing the same thing, recasting as pointers as I see it. Does this mean host->h_addr is a reference or can anything be recast as a pointer, say an int or a pointer to a pointer to a char, a pointer to a pointer to a pointer to an array?

ETA: I guess my question is: what sort of things could host->h_addr possibly be aside from a reference?

ETA2: The application looks like this in regards to the host pointer:

    struct hostent *host;
    if ((host = gethostbyname("localhost")) == NULL)

Should there be an
malloc(sizeof(hostent))
between those two lines?

Does this mean host->h_addr is a reference

No, it means that host->h_addr is a pointer. A pointer and a reference are very different things.

Casting in this way is something the compiler knows how to do for a number of types. One kind of pointer to another kind of pointer is always allowed, as all pointers are the same size and do the exact same thing; they all just store a single number, and the only difference between an int-pointer and a long-pointer is that the compiler will treat what the int-pointer is pointing at as an int, and similarly for the long-pointer. It will also treat different kinds of pointer differently for pointer arithmetic, but again, that's really about what the pointer is pointing at.

If you asked the compiler to simply cast an int as an int-pointer, it should complain. That's not to say it can't be done (this is C/C++, and you can do what you like) but you have to be a bit more clever about it.

Should there be an
malloc(sizeof(hostent))
between those two lines?

No. This struct hostent *host; creates a pointer, that is currently pointing at some random memory. This gethostbyname("localhost") looks like an attempt to get a pointer to some existing host object, so this host = gethostbyname("localhost") is an attempt to make the pointer point at some existing host object, and the final ==NULL on the end is a check to see if the pointer is now pointing at a host object, or if it has the NULL value (so the function gethostbyname presumably returns NULL if it can't return a pointer to the host object you asked for.

There is no need for you to allocate any memory here because you are not going to create a new host object. The address of a host object is going to be given to you by the gethostbyname function.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.