malloc in c, struct - c

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.

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.

Trouble with structs and strings

I made a linked list whose nodes hold 4 string values. When I call the newNode function, an error says 'Node has no member named familyName', as well as the other members. My code:
I am really confused with how strings work in structs.
Your immediate problem is the type definition. You cannot call malloc() from within there, all you can do is define the fields. The memory allocation must come later. So, it should be:
typedef struct node{
char *familyName;
char *firstName;
char *address;
char *phoneNumber;
struct node *link;
}Node;
You'll strike another problem (run-time rather than compile-time) once you fix that. When you do something like:
p -> familyName = famName;
that simply copies the pointer into your structure, and the pointer is always the memory location of familyName in main().
That means every node will point to the same memory, and you're continuously updating that memory.
You won't notice the problem with the code as it stands, since you're only asking for one record. But it will become an issue when you start looping to get more records.
Your best bet is to use something like strdup() to make a copy of the string passed in, then each node will have its own memory location for strings:
p -> familyName = strdup (famName);
(don't forget to also free() the memory for each field once you're finished with it).
In the unlikely event your C implementation doesn't have a strdup(), see here.
There are several problems:-
It is not allowed to allocate memory when declaring a structure. Either, do the malloc inside your newNode() method Or, declare the structure like char familyName[50].
Result of malloc should not be casted.
It is better to use strcpy (or strdup) when copying strings

C - transferring information to a struct (specifically an array of strings)

This seems to be a very simple problem but I can't quite figure out which part is causing it. Basically, I have a struct that just contains an array of strings
struct command_stream{
char **tokens;
};
typedef struct command_stream *command_stream_t;
command_stream_t test;
Then later on, I parse some strings into shorter ones and end up with another array of strings
char **words = *array of strings*
words contains the correct information I want, I looped through and printed out each element to make sure I wasn't getting a faulty string. So now I just point tokens to words
test->tokens = words;
But it gives me a segmentation fault. I'm not sure why though. They're both pointers, so unless I'm missing something obvious...
EDIT: The function as a whole has to return a pointer, which is why it was set up like this, which I keep forgetting. But I think I've got it, if I just create a new typedef
typedef struct command_stream command_stream_s;
command_stream_s new_command_stream;
and just return
&new_command_stream;
That should work right? Even though new_command_stream itself isn't a pointer.
From your code excerpt, it seems that you have not declared the struct. You have successfully declared a pointer to the struct command_stream_t test; but this pointer does not point to anywhere yet.
You need to allocate memory for your struct in some way and make test reference it. For instance:
command_stream_t test =
(command_stream_t) malloc(sizeof(struct command_stream));
This way you can successfully use:
test->tokens = words;
as you intended.
Note that you don't need to use malloc to allocate the memory. The pointer can reference a local/global variable as long as it has memory associated to it (N.B. if you use a local var don't use the pointer outside the declaration scope of that var).
typedef struct command_stream *command_stream_t;
command_stream_t test;
This makes "test" a pointer. There is no memory allocated for the structure.
You need to allocate memory for the structure and make the test pointer point to the block of memory before you can dereference by saying -
test->tokens = words;
Do this:
typedef struct command_stream command_stream_t;
command_stream_t test;
test.tokens = words;
The difference is that, command_stream_t is no more a pointer type, it is the actual structure.

Concern about struct pointer

I'm doing a project where our professor has given us code with variables and prototype declarations that we are unable to change. One is a struct, with a pointer to that struct is typedef'd as pStudentRecord:
typedef struct
{
char* firstName;
char* lastName;
int id;
float mark;
}* pStudentRecord;
With a pointer to this type called g_ppRecords. This will be a dynamic array of pointers to the structs above.
Here's where my question comes in. The records will be read from a file. If the filename specified doesn't exist then it creates a new one. I'm initializing the g_ppRecords pointer whenever the user adds the first new record:
if(!n) //where n = number of records
g_ppRecords = (pStudentRecord*) malloc(sizeof(pStudentRecord));
g_ppRecords[n] = (pStudentRecord) malloc(16);
This code works every time I've ran it so far, but I'm not sure how. If I add more records then a new pointer (pStudentRecord) will be created in the next position in g_ppRecords. By my understanding, I haven't allocated the space for that new pointer, yet every time it works without even a hint of a problem. I can access the members of the new structs fine and I'm not getting a heap corruption error or access violation or anything like that. Are my concerns correct or am I doubting myself?
Based on the code that you've shown, your concerns are valid.
This line:
g_ppRecords = (pStudentRecord*) malloc(sizeof(pStudentRecord));
Allocates only enough space for a single pStudentRecord. Think of this as an array of pStudentRecord with only a single element, at g_ppRecords[0].
If I add more records then a new pointer (pStudentRecord) will be created in the next position in g_ppRecords.
Now the problem is what might happen when you do what you've described here. What happens when you add a new pointer? Unless you use realloc to get more space for g_ppRecords, you don't have room in that array for more pointers to records. If you malloc a new pointer at the second element, i.e.:
g_ppRecords[1] = (pStudentRecord) malloc(16);
Then you're using memory, g_ppRecords[1], that you haven't allocated. This may appear to work, but this memory doesn't belong to you. Keep adding new pointers and eventually your program will break. Or your program may break because of something totally unrelated in another part of your code.
The fix is that you should initially allocate your array so that it can hold multiple pointers, instead of only one. How can you do this with your first malloc line?
I should add that when you allocate memory for a struct using malloc(16) you're making assumptions about the data structure that you shouldn't make, specifically that the struct will always occupy 16 bytes. Given your typedef: straight to a pointer from an anonymous struct, you can change that 16 to something more general, but this isn't directly related to your question, and is something that you should ask your professor about.
As a general rule, try to avoid malloc( sizeof( type )), especially when the type is obfuscated by a typecast. It is much safer to call sizeof on a variable: malloc( sizeof x ). Also, in C, you should not cast the return from malloc. In other words, instead of allocating space for only one record with:
g_ppRecords = (pStudentRecord*) malloc(sizeof(pStudentRecord));
it would be better to allocate space for n records by writing:
g_ppRecords = malloc( n * sizeof *g_ppRecords );
typedef struct
{
char* firstName;
char* lastName;
int id;
float mark;
}* pStudentRecord;
This is an anonymous struct. A bit weird here, but maybe to teach you something. Do this to create a new one:
pStudentRecord ptr;
ptr = malloc(sizeof(*ptr));
This will automatically malloc the right amount of memory.
You've still got problems because you need to malloc the array to hold the pointers. For that do this:
pStudentRecord* g_ppRecords = malloc(n * sizeof(pStudentRecord));
You can then use g_ppRecords like this:
pStudentRecord ptr = g_ppRecords[3];
Putting it all together we have our custom allocator:
pStudentRecord* g_ppRecords = malloc(n * sizeof(pStudentRecord));
for (size_t i = 0; i < n; ++i)
{
pStudentRecord ptr;
g_ppRecords[i] = malloc(sizeof(*ptr));
}
I wrote all this without compiling and testing, so there may be errors (but its not my homework :-) )

Using pointers and structs

Hello i'm not sure if I'm understand the following piece of code. I would glad if someone could read my explanations and correct me if I'm wrong.
So first of all I'm declaring a struct with three arrays of char and an integer.
struct Employee
{
char last[16];
char first[11];
char title[16];
int salary;
};
After that I declare a function which takes three pointers to char and an integer value. This function uses malloc() and sizeof() to create a struct on the heap. Now this creations of the object on the heap is not really clear to me. When I use struct Employee* p = malloc(sizeof(struct Employee)), what happens there exactly? What happens when I use the function struct Employee* createEmployee (char* last, char* first, char* title, int salary) several times with different input. I know that I will get back a pointer p but isn't that the same pointer to the same struct on the heap. So do I rewrite the information on the heap, when I use the function several times? Or does it always create a new object in a different memory space?
struct Employee* createEmployee(char*, char*, char*, int);
struct Employee* createEmployee(char* last, char* first, char* title, int salary)
{
struct Employee* p = malloc(sizeof(struct Employee));
if (p != NULL)
{
strcpy(p->last, last);
strcpy(p->first, first);
strcpy(p->title, title);
p->salary = salary;
}
return p;
}
I would be glad if someone could explain it to me. Thank you very much.
The malloc function allocates some new bytes on the heap and returns the pointer.
So the createEmployee function allocates new memory every time it's called, then fills it with some data (in an unsafe way - consider using strncpy instead) and returns the pointer to that memory. It will return a different pointer every time it's called.
Each instance you create with this function will exist as long as you don't call free on its pointer.
Your first question is a question about malloc. You might get better results searching for "How does malloc work?" The answer is different for different operating systems and C libraries.
The createEmployee function creates an all-new struct Employee every time it is called.
I also see that createEmployee is written in a very dangerous way. No checking is done to ensure that the strings fit into their destinations before calling strcpy. This is how buffer overflows are created.
malloc assigns you a block of memory equal to its first argument, in this case the size of the Employee.
Every time you call createEmployee, you call malloc a separate time, and every time you call malloc, it gives you a fresh piece of memory.
This is what allows you to have different employees: if they all used the same memory, you would only be able to create one.
This is why calling free, and freeing that memory is important: the operating system has no other way of knowing whether you're using the memory or not.
If you want to edit an existing employee, maintain a pointer reference to it, and add a strcpy(p->title, newTitle); to change its title to newTitle.
Also, something that has been mentioned, strcpy is dangerous, as it will continue to write its strings regardless of whether it has exceeded the 11 characters allotted for it.
Every time you call malloc(), you're telling it to give you a new chunk of memory, at least as long as you've asked for, not currently in use anywhere else. So the following gives you three different pointers:
void *p1 = malloc(100);
void *p2 = malloc(100);
void *p3 = malloc(100);
It's like hitting a button on a vending machine. Each time, you get a different candy bar that conforms to your requests ("Caramilk" for instance.)

Resources