How do I access members of this structure in C? - c

I'm working with this structure in C:
/** This structure describes an Internet host address. */
typedef struct pj_hostent
{
char *h_name; /**< The official name of the host. */
char **h_aliases; /**< Aliases list. */
int h_addrtype; /**< Host address type. */
int h_length; /**< Length of address. */
char **h_addr_list; /**< List of addresses. */
} pj_hostent;
I can access the h_name part of the structure fine like this:
strcpy(test1, he->h_name); // copy part of struct into char[] array
and it contains a meaningful "sip2" value. However, when I try to access the elements of h_addr_list like this:
strcpy(test1, he->h_addr_list[0]);
I get meaningless jibberish.
What's the correct way in C to access values like this?

h_addr_list[0] is not a string, it is a pj_in_addr, which is a 32-bit integer which is not null terminated.
printf() it with %d or %x, not %s.
See PJLIB Reference: Network Address Resolution for an example of use.

You are accessing it correctly. That field really does contain gibberish.

Just because it is declared as a char** does NOT mean that it is an array of strings.
It may be a pointer to a byte-buffer of unknown format. (ie. jibberish)
You should check any available documentation or other source code for details of exactly what h_addr_list is, and how it should be interpreted.

The struct only contains a pointer. You need to allocate some storage for that pointer to point at before you can use it. As it is, the pointer almost certainly just contains a (more or less) random value. When you use that as a target in your call to strcpy, you're overwriting that random memory location -- which can and will lead to major problems elsewhere.
h_addr_list is pretty much the same way -- it's just a pointer to a pointer. That'll (normally) be used to refer to an array of strings, but something has to allocate that array of strings before it can be put to any meaningful use. Given the similarity to a hostent structure, along with this structure there's presumably some analog to (or wrapper around) gethostbyname and/or gethostbyaddress that initializes this. In the case of the wrapper (which I'd judge the more likely of the two), it probably gets the correct data in a hostent, and then copies data from the hostent to this structure.

A short Example that does work. Remember that allocating for the struct does not allocate for the pointer.
typedef struct pj_hostent
{
char *h_name; /**< The official name of the host. */
char **h_aliases; /**< Aliases list. */
int h_addrtype; /**< Host address type. */
int h_length; /**< Length of address. */
char **h_addr_list; /**< List of addresses. */
} pj_hostent;
int _tmain(int argc, _TCHAR* argv[])
{
char* s[]= {"this","is","couple of words"};
pj_hostent hst = {"high",s,3,4,s };
char buff[255] = {};
//Access as a local initialized struct
strcpy(buff,hst.h_addr_list[0]);
printf("%s\n",buff);
pj_hostent * he = & hst;
//Access as a pointer
strcpy(buff,he->h_addr_list[0]);
printf("%s\n",buff);
gets(buff);
}

If you never initialized/allocated memory for those pointers, you would get jibberish and/or segmentation faults because they are pointing to random points in memory.

strcpy assumes that you have already allocated memory to the character pointer. So, probably, the pointer is still having a NULL value.

struct elements are accessed with the dot operator
strcpy(test1, he.h_addr_list[0]);
elements of structs that are "pointed" to are accessed with the -> operator
strcpy(test1, he->h_addr_list->[0]);
If you're getting gibberish, then either test1 isn't big enough, h_addr_list isn't pointing to an array of char*, or the first element of the array is actually gibberish.

Related

Memory allocation of nested char pointer

I have a question regarding the allocation of memory for a given char pointer inside a struct. The following typedef bson_value_t is given by an API and I would like to use it inside my own typedef ObjectInfo, shown in my code:
typedef struct _bson_value_t {
bson_type_t value_type;
union {
int64_t v_int64;
int32_t v_int32;
int8_t v_int8;
double v_double;
struct {
uint32_t len;
char *str;
} v_utf8;
} value;
} bson_value_t;
typedef struct _ObjectInfo {
char key[100];
bson_value_t value;
} ObjectInfo;
I have other data packages that contain hundreds of these ObjectInfo types, but all simply initalized like:
typedef _DataPackage {
ObjectInfo single;
ObjectInfo multiple[100];
...
} Datapackage;
So they do not contain any usefull data yet. I would like to use strcpy to put a string to the location where char *str is pointing. But as far as I know that does not work because there is no allocated memory where *str is pointing to, right?
My question would be, how do I accomplish that without changing the given typedef bson_value_t? Do I need to allocate memory for any one bson_value_t that I initialized?
strcpy(DataPackage.single.value.value.v_utf8.str, "test");
That does not work, unless I change it to:
strcpy(&DataPackage.single.value.value.v_utf8.str, "test");
but this is giving me compiler warnings.
I would like to use strcpy to put a string to the location where char *str is pointing. But as far as I know that does not work because there is no allocated memory where *str is pointing to, right?
Right.
My question would be, how do I accomplish that without changing the given typedef bson_value_t? Do I need to allocate memory for any one bson_value_t that I initialized?
No, you do not (for this purpose) need to dynamically allocate memory for any bson_value_t. The space, if any, to which any of those value.v_utf8.str members point will be external to the the bson_value_t, so arranging for that memory is a separate consideration.
As far as the data structure itself is concerned, the string data could be dynamically allocated, or they could be statically allocated (such as the contents of a string literal), or they could even be a locally-declared array (automatically allocated), though this last will present issues if the lifetime of the string data is shorter than that of the bson_value_t.
However, do make sure that you know what assumptions are made by the library from which you are drawing this. For example, if any of its functions assume that they can reallocate space to provide for lengthening the string, or if they assume that they can modify the contents in place, then such assumptions affect what kind of storage you need to provide.

What does struct hostent stands for?

A pointer to hostent is the struct returned by gethostbyname().
Exact function signature : struct hostent* gethostbyname(const char*)
And I have no idea what the 'ent' part means here at the end of hostent.
I get very forgetful when I try to memorize that I don't understand, so please help me out.
A quick search on GitHub points to basedefs/netdb.h (definitions for network database operations)
The <netdb.h> header shall define the hostent structure that includes at least the following members:
char *h_name Official name of the host.
char **h_aliases A pointer to an array of pointers to
alternative host names, terminated by a
null pointer.
int h_addrtype Address type.
int h_length The length, in bytes, of the address.
char **h_addr_list A pointer to an array of pointers to network
addresses (in network byte order) for the host,
terminated by a null pointer.
From there, the official documentation for gethostbyaddr() includes:
Entries shall be returned in hostent structures.
The gethostbyaddr() function shall return an entry containing addresses of address family type for the host with address addr.
The len argument contains the length of the address pointed to by addr.
The gethostbyaddr() function need not be reentrant. A function that is not required to be reentrant is not required to be thread-safe.
Entries shall be returned in hostent structures.
Upon successful completion, these functions shall return a pointer to a hostent structure if the requested entry was found, and a null pointer if the end of the database was reached or the requested entry was not found.
So there you have it: ent for entry. Not entity.

malloc in c, struct

I made a struct like this:
struct a{
char *name;
char *value;
struct a *next;
};
when I malloc for memory at first time, it's ok, and I can set 'name' and 'value' a corresponding value.
but when I malloc for the second time, errors come. And It's a cgi, just show me "500 Internal server error".
I changed the pointer 'name' and 'value' to array, everything works.
I thought maybe the complier doesn't know how much memory to assign.
And do you have some ideas with this? I will appreciate every answer!
struct a {
char *name;
char *value;
struct a *next;
};
struct a *head = malloc(sizeof *head);
The above allocates space for a single struct a object, but it doesn't initialize any of hte three pointers contained in a struct a. In particular, if you want name and value to point to strings, you'll need to allocate space for those strings:
head->name = malloc(5);
strcpy(head->name, "Fred");
head->value = malloc(8);
strcpy(head->value, "abcdefg";
This is considerably oversimplified. 5 and 8 are "magic numbers"; you should specify the sizes in a way that will remain consistent if you change the initial values. And you should always check whether malloc() returns a null pointer (even if you just terminate the program with an error message).
If you don't initialize name and value to point to some chunk of allocated memory, you might still be able to initialize what they point to (e.g., by doing the strcpys above without the mallocs). More precisely, the system won't necessarily diagnose the error.
Finally, you'll need a call to free() corresponding to each malloc() call.
Note that this is largely a guess based on your description. If you can show us your actual code, we can help you better.
If you use malloc with sizeof(struct a) it's just going to assign enough space to store the pointers name and value. You want these to be char arrays, then it'll know how much space to set aside for each instance of a.

C language : why do i get NULL?

about the code:
tp is a pointer to a certain struct which contains a table.
the table is a pointer to a pointer of a differnt struct,used as an array.
size is just the size of the table.
im sending these veriables to a function in order to initialize all the cells in the
array to NULL.
this line:
initArr(tp->table,tp->size);
sends them to this function:
void initArr(ObjectP* array,int size)
{
int i;
for (i = 0; i < size; ++i)
{
array[i]=NULL;
}
}
using the eclipse debugger i can see that the objects in the array are infact
being initialized to NULL, but when the method ends,
tp->table is NULL.
pointers gone wild?
help please.
the structs:
table:
typedef struct Table
{
size_t size;
hashFcn hash;
printFcn print;
comparisonFcn comp;
ObjectP* table;
int duplicated;
}Table;
object:
typedef struct Object
{
void *key;
ObjectP pointsTo;
}Object;
Arrays and pointers are similar but different.
An array of pointers can be represented as a number of continuous pointers in memory (with an address of where the first pointer in the array resides).
Under such a circumstance tp->table is exactly the same as tp->table[0], but the [0] is assumed (because it has the same address). In systems that are implemented in this manner, the tp->table specifies an address, and the offset from that address (to get to the element of the array) is represented as a value times the datatype size (or one pointer's size in your case).
tp->table (the base address 0x00000100)
tp->table[0] (the address 0x00000100 + 0 * sizeof(... pointer ...) = 0x00000100)
tp->table[1] (the address 0x00000100 + 1 * sizeof(... pointer ...) = 0x00000104 (some systems only))
tp->table[2] (the address 0x00000100 + 2 * sizeof(... pointer ...) = 0x00000108 (some systems only))
So your debugger might actually be printing out tp->table which is exactly equivalent to tp->table[0] depending on your compiler's implementation.
The code as presented seems wrong (you are returning something from a void function!), but I'm going to take a wild guess and assume that in your actual code, you are trying to set "array" to something (probably via malloc) inside initArr, in which case we have a classic gotcha: You are passing tp->table by value, so it does not get changed by initArr: initArr operates on a local copy of tp->table, which is discarded when initArr ends :)
Edit:
Doh - now you've posted the update, it looks like my guess was wrong. :/ Imagine the kudos if I'd got it right! :)

Reading and Writing Structures [C]

IMPORTANT EDIT:
Sorry everyone, i made a big mistake in the structure.
char *name; is meant to be outside of the structure, written to the file after the structure.
This way, you read the structure, find out the size of the name, then read in the string. Also explains why there is no need for a null terminator.
However, i feel somewhere, my actual question has been answered. If someone would like to edit their responses so i can choose one which is the best fitting i'd appreciate it.
Again, the question I was asking is "If you read in a structure, are you also reading in the data it holds, or do you need to access it some other way".
Sorry for the confusion
For an assignment, I've been tasked with a program which writes and reads structures to a disk (using fread and fwrite).
I'm having trouble grasping the concept.
Lets say we have this structure:
typedef struct {
short nameLength;
char* name;
}attendenceList;
attendenceList names;
now assume we give it this data:
names.name = "John Doe\0";
names.nameLength = strlen(names.name); /*potentially -1?*/
and then we use fwrite... given a file pointer fp.
fwrite(&names,sizeof(names),1,fp);
now we close the file, and open it later to read in the structure.
the question is this: when we read in the structure, are we also reading in the variables it stores?
Can we then now do something like:
if(names.nameLength < 10)
{
...
}
Or do we have to fread something more then just the structure, or assign them somehow?
Assuming the fread is:
fread(&names,sizeof(names),1,fp);
Also assuming we've defined the structure in our current function, as above.
Thanks for the help!
You have a problem here:
fwrite(&names,sizeof(names),1,fp);
Since attendenceList saves the name as a char * this will just write out the pointer, not the actual text. When you read that back in, the memory the pointer is referencing will most likely have something else in it.
You have two choices:
Put a character array (char names[MAXSIZE]) in attendenceList.
Don't write the raw data structure, but write the necessary fields.
You're writing the memory layout of the structure, which includes its members.
You'll get them back if you read the structure back in again - atleast if you do it on the same platform, with a program compiled with the same compiler and compiler settings.
Your name member is declared just as a char, so you can't store a string in it.
If name was a pointer like this:
typedef struct {
short nameLength;
char *name;
}attendenceList;
You really should not read/write the struct to a file. You will write the structure as it's laid out in memory, and that includes the value if the name pointer.
fwrite knows nothing about pointers inside your structure, it will not follow pointers and also write whatever they point to.
when you read the structure back again, you'll read in the address in the name pointer, and that might not point to anything sensible anymore.
If you declare name as an array, you'll be ok, as the array and its content is part of the structure.
typedef struct {
short nameLength;
char name[32];
}attendenceList;
As always, make sure you don't try to copy a string - including its nul terminator- to name that's larger than 32. And when you read it back again. set yourstruct.name[31] = 0; so you are sure the buffer is null terminated.
To write a structure, you'd do
attendenceList my_list;
//initialize my_list
if(fwrite(&my_list,sizeof my_list,1,f) != 1) {
//handle error
}
And to read it back again:
attendenceList my_list;
//initialize my_list
if(fread(&my_list,sizeof my_list,1,f) != 1) {
//handle error
}
}
I'm assuming you meant char* name instead of char name.
Also sizeof(name) will return 4 because you are getting the size of a char* not the length of the char array. So you should write strlen(name) not sizeof(name) inside your fwrite.
In your above example I would recommend storing the string exact size without the null termination. You don't need to store the string length as you can get that after.
If you are reading just a string from a file, and you wrote the exact size without the null termination. Then you need to manually null terminate your buffer after you read the data in.
So make sure you allocate at least the size of your data you are reading in plus 1.
Then you can set the last byte of that array to '\0'.
If you write a whole struct at a time to the buffer, you should be careful because of padding. The padding may not always be the same.
when we read in the structure, are we also reading in the variables it stores?
Yes you are, but the problem you have is that as I mentioned above you will be storing the pointer char* (4 bytes) and not the actual char array. I would recommend storing the struct elements individually.
You ask:
now we close the file, and open it later to read in the structure. the question is this: when we read in the structure, are we also reading in the variables it stores?
No. sizeof(names) is a constant value defined at compile time. It will be the same as
sizeof(short) + sizeof(void*) + some_amount_of_padding_to_align_things
it will NOT include the size of what names.name points to, it will only include the size of the pointer itself.
So you have two problems when writing this to a file.
you aren't actually writing the name string to the file
you are writing a pointer value to the file that will have no meaning when you read it back.
As your code is currently written, When you read back the names, names.name will point to somewhere, but it won't point to "John Doe\0".
What you need to do is to write the string pointed to by names.name instead of the pointer value.
What you need to do is sometimes called "flattening" the structure, You make a structure in memory that contains no pointers, but holds the same data as the structure you want to use, then you write the flattened structure to disk. This is one way to do that.
typedef struct {
short nameLength;
char name[1]; // this will be variable sized at runtime.
}attendenceListFlat;
int cbFlat = sizeof(attendenceListFlat) + strlen(names.name);
attendenceListFlat * pflat = malloc(cbFlat);
pflat->nameLength = names.nameLength;
strcpy(pflat->name, names.name);
fwrite(pflat, cbFlat, 1, fp);
The flattened structure ends with an array that has a minimum size of 1, but when we malloc, we add strlen(names.name) so we can treat that as an array of strlen(names.name)+1 size.
A few things.
Structures are just chunks of memory. It's just taking a bunch of bytes and drawing boundaries on them. Accessing structure elements is just a convenient way of getting a particular memory offset cast as a particular type of data
You are attempting to assign a string to a char type. This will not work. In C, strings are arrays of characters with a NULL byte at the end of them. The easiest way to get this to work is to set a side a fixed buffer for the name. When you create your structure you'll have to copy the name into the buffer (being very careful not to write more bytes than the buffer contains). You can then write/read the buffer from the file in one step.
struct attendanceList {
int namelen;
char name[256]; //fixed size buffer for name
}
Another way you could do it is by having the name be a pointer to a string. This makes what you're trying to do more complicated, because in order to write/read the struct to/from a file, you will have to take into account that the name is stored in a different place in memory. This means two writes and two reads (depending on how you do it) as well as correctly assigning the name pointer to wherever you read the data for the name.
struct attendanceList {
int namelen;
char* name; //the * means "this is a pointer to a char somewhere else in memory"
}
There's a third way you could do it, with a dynamically sized struct using a trick with a zero length array at the end of a struct. Once you know how long the name is, you allocate the correct amount (sizeof(struct attendanceList) + length of string). Then you have it in one contiguous buffer. You just need to remember that sizeof(struct attendanceList) is not the size you need to write/read. This might be a little confusing as a beginning. It is also kind of a hack that's not supported under all compilers.
struct attendanceList {
int namelen;
char name[0]; //this just allows easy access to the data following the struct. Be careful!
}

Resources