Changing values in elements of an array of structs - c

I am working on an assignment and ran into challenging problem. As far as I'm concerned and from what I've learnt the code that follows should be correct however it does not work. Basically what I am trying to is copy a string value into the variable member of a structure the is part of an array passed into a method as a pointer. What am I missing?
typedef struct
{
char * name; //variable in struct I am trying to access
} Struct;
void foo(Struct * arr) //array of Structs passed into function as a pointer
{
int i = 0;
while(i++ < 2)
{
arr[i].name = malloc(sizeof(char *)); //assigning memory to variable in each Struct
arr[i].name = strdup("name"); //copying "name" to variable in each Struct
printf("C - %s\n", arr[i].name); //printing out name variable in each Struct
}
}
main()
{
Struct * arr; //defining pointer
arr = calloc(2, sizeof(Struct)); //allocating memory so pointer can hold 2 Structs
foo(arr); //calling function foo passing pointer into function
return 0;
}
This code compiles and runs however it does not do what it is designed to do. Forgive me if it is something trivial. I am new to the language C

Two issues:
while(i++ < 2) This line changes the value of i as soon as it checks it, so your loop body will not be the same as it was checked.
arr[i].name = strdup("name"); overwrites the value of the .name pointer, causing a memory leak of the memory you malloc()'ed earlier.

Extending on 2 pointed out correctly already,
arr[i].name = strdup("name");
Even if you use following instead of above,
strcpy(array[i].name, "name");
you haven't allocated enough bytes to store the string i.e. this is wrong
arr[i].name = malloc(sizeof(char *));
// even if pointer is 8 byte here, concept isn't right
Should be something like
arr[i].name = malloc(strlen("name")+1);
// or MAX_SIZE where it is greater than the possible "name".
Or better yet, remove the malloc at all, strdup takes care of allocation itself

This is not answering your question directly, but addresses an issue to big to put into a comment...
Additional issue: You probably did not intend to allocate only a (char *) worth of memory to a variable intended to hold at least "name". Change;
arr[i].name = malloc(sizeof(char *));
to:
arr[i].name = malloc(sizeof(char)*strlen("name")+1); //+1 for '\0'
or better yet, use char *name="name";, then:
arr[i].name = malloc(sizeof(char)*strlen(name)+1);
Even more general (and better):
char *name;
name = malloc(strlen(someInputString)+1);
//do stuff with name...
free(name);
Now, you can allocate name to any length needed based on the length of someInputString.
[EDIT]
Etienz, I wanted to address one more thing, alluded to by #H2CO3 above, but not really explained, that I think might be useful to you:
Regarding your desire to have room for two structs, because you typedef'd your struct, you can simply do something like this: (but I am going to change the name you used from Struct to NAME :) The whole point being that when a struct is created as an array, you do not need to use calloc or malloc to create space for them, it is done as shown below...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char *name;
}NAME;
//use new variable type NAME to create global variables:
NAME n[2], *pN; //2 copies AND pointer created here
//prototype func
int func(NAME *a);
int main()
{
pN = &n[0]; //pointer initialized here
func(pN); //pointer used here (no malloc or calloc)
printf("name1 is %s\nname 2 is %s", pN[0].name, pN[1].name);
return 0;
}
int func(NAME *a)
{
char namme1[]="andrew";
char namme2[]="billebong";
//You DO have to allocate the members though
a[0].name = malloc(strlen(namme1)+1);
a[1].name = malloc(strlen(namme2)+1);
strcpy(a[0].name, namme1);
strcpy(a[1].name, namme2);
return 0;
}

Related

Heap corruption on malloc/calloc of char pointer field in struct

I have a struct defined like this
typedef struct {
char* Value;
unsigned int Length;
} MY_STRUCT;
I'm creating an array of these structs using calloc:
MY_STRUCT* arr = (MY_STRUCT*)calloc(50, sizeof(MY_STRUCT));
Then, in a loop, I'm accessing each struct and trying to allocate and assign a value to the Value field using calloc and memcpy:
int i;
for(i = 0; i < 50; i++)
{
MY_STRUCT myStruct = arr[i];
int valueLength = get_value_length(i);//for sake of example, we can assume that this function returns any value [1-99]
myStruct.Length = valueLength;
myStruct.Value = (char*) calloc(valueLength, sizeof(char));
memcpy(myStruct.Value, get_value(i), valueLength); //assume get_value(i) returns char* pointing to start of desired value
}
This code block crashes on the calloc line with Visual Studio indicating heap corruption. It doesn't fail the first time through the loop. Instead, it fails on the second pass when I'm trying to allocate a length 20 char array (first pass is length 5). I've tried using malloc as well, and I've tried using recommendations in:
Heap Corruption with malloc, struct and char *
Do I cast the result of malloc?
Nothing seems to mitigate the problem. I am originally a managed code programmer so my knowledge of memory allocation and management is not always the best. I'm sure I'm doing something boneheaded, but I'm not sure what. Any help would be greatly appreciated. Thank you!

How do you use malloc to allocate space for an array of structures?

I'm currently working on dynamically allocating my array of structures and I'm unsure how to continue. This is my structure:
struct Word_setup
{
char word[M];
int count;
} phrase[N];
I know malloc returns a pointer to a block of memory, but I'm not sure how this works when it comes to an array of structures.
If anyone could please clarify that would be much appreciated!
Probably you meant:
struct Word_setup {
char word[M];
int count;
};
It's a good idea to avoid defining variables in the same line as a struct definition anyway, to help with code readability.
Then you can allocate an array of these:
int main()
{
struct Word_setup *phrase = malloc(N * sizeof *phrase);
// use phrases[x] where 0 <= x < N
phrase = realloc(phrase, (N+5) * sizeof *phrase);
// now can go up to phrases[N+4]
free(phrase);
}
Of course you should check for failure and abort the program if malloc or realloc returns NULL.
If you also want to dynamically allocate each string inside the word then there are a few options; the simplest one to understand is to change char word[M] to char *word; and each time you allocate a phrase, write the_phrase.word = malloc(some_number); . If you allocate an array of words you'll need to loop through doing that for each word.
I suppose that N and M is a compile-time known constants. Then just use sizeof, .e.g.
struct Word_setup*ptr = malloc(sizeof(struct Word_setup)*N);
Maybe you want a flexible array member. Then, it should always be the last member of your struct, e.g.
struct Word_setup {
int count;
unsigned size;
char word[]; // of size+1 dimension
};
Of course it is meaningless to have an array of flexibly sized structures -you need an array of pointers to them.

Allocating memory for array of structs

I've a struct like the one who follows:
typedef struct author
{
char letter;
char *name[200];
int counter;
} Aut, *i_aut;
It consists of a char, and array of "Strings" and int. My goal is to allocate space in memory for an array of 30 of this kind of structs, therefore I tried something like the following:
i_aut lista_autores=calloc(30,sizeof(Aut));
However, it always returns "segmentation fault". I tried to initialize one at a time too, but with the same result. My question is, how do I allocate memory of this kind and how can I access it later?
Thank you in advance, and sorry for any typo.
the struct member name is an array of 200 pointers.
You may want to assign the result of malloc to elements of the array.
struct author *i_aut;
i_aut = malloc(sizeof *i_aut);
if (i_aut) {
for (size_t k = 0; k < 200; k++) {
i_aut->name[k] = malloc(30);
if (!i_aut->name[k]) /* error */;
/* DONT FORGET TO FREE EACH NAME LATER ON */
}
free(i_aut);
}
try using this
struct author **i_aut;
i_aut=(struct author **)malloc(30*sizeof(struct author*));
for(i=0;i<30;i++)
i_aut[i]=(struct *)malloc(sizeof(struct author));
after this you need not allocate space for name[] seperately.
you have array of 30 elements of type struct author*
and you can access all three type using
i_aut[i]->letter;
i_aut[i]->name[j];
i_aut[i]->counter;
here i<30

Declare and allocate memory for an array of structures in C

I'm trying to declare and allocate memory for an array of structures defined as follows:
typedef struct y{
int count;
char *word;
} hstruct
What I have right now is:
hstruct *final_list;
final_list = calloc (MAX_STR, sizeof(hstruct));
MAX_STRbeing the max size of the char word selector.
I plan on being able to refer to the it as:
final_list[i].count, which would be an integer and
final_list[i].word, which would be a string.
ibeing an integer variable.
However, such expressions always return (null). I know I'm doing something wrong, but I don't know what. Any help would be appreciated. Thanks.
A struct that contains a pointer doesn't directly holds the data, but holds a pointer to the data. The memory for the pointer itself is correctly allocated through your calloc but it is just an address.
This means that is your duty to allocate it:
hstruct *final_list;
final_list = calloc(LIST_LENGTH, sizeof(hstruct));
for (int i = 0; i < LIST_LENGTH; ++i)
final_list[i].word = calloc(MAX_STR, sizeof(char));
This requires also to free the memory pointed by final_list[i].word before releasing the array of struct itself.

Copy two structs in C that contain char pointers

What is the standard way to copy two structs that contain char arrays?
Here is some code:
#include stdio.h>
#include string.h>
#include stdlib.h>
typedef struct {
char* name;
char* surname;
} person;
int main(void){
person p1;
person p2;
p1.name = (char*)malloc(5);
p1.surname = (char*)malloc(5);
strcpy(p1.name, "AAAA");
strcpy(p1.surname, "BBBB");
memcpy(&p2, &p1, sizeof(person));
free(p1.name);
printf("%s\n", p2.name);
return 0;
}
The line printf("%s\n", p2.name); does not print something, because I freed the buffer.
The problem with my structs is that they are bigger than struct person. They contain hundreds of char pointers, and I have to copy every member one by one.
Is there another way to copy two structs that contain char arrays without using malloc and strcpy for every member?
You have no choice but provide a copy function yourself:
void copy_person(person *dst, const person *src)
{
dst->name = malloc(strlen(src->name) + 1);
dst->surname = malloc(strlen(src->surname) + 1);
strcpy(dst->name, src->name);
strcpy(dst->surname, src->surname);
}
which may be more elaborated than that: checking for errors, factoring the strlen + strcpy in an auxilliary function, etc.
That's what copy constructors in C++ are for.
Yes, copying struct that contain char arrays will work without any problem, but struct with char pointers (or any type of pointer for that matter) you will have to do manually.
Also note that the cast of malloc's return type is not needed in C (it is in C++) and can hide a missing prototype for malloc.
To elaborate on the answer of Alexandre C. you might want to do the malloc() as a single operation so that a free() is also simple.
This approach provides a degree of protection in that the single malloc() will either succeed or fail so that you would not have a problem of malloc() failing midway through constructing a copy. With this approach you would mix person with pointers to person that have been malloced so you might want to have two different data types something along the lines of the following in order to better mark which is which.
I have provided two alternatives for the copying with one using C Standard library functions strcpy() and strlen() and the other using a simple function that does a straight copy and returns a pointer to where it left off in the destination buffer.
I have not tried to compile this example so there may be problems with it.
There is one possible concern with this approach. Since the individual strings are not malloced you may run into a problem if you are moving the individual strings around using their pointers with the idea that each of the individual strings is its own malloced area of memory. This approach assumes the entire object is wanted or none of it is wanted.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
char* name;
char* surname;
char* address1;
} person, *personptr;
// copy a string to destination string return pointer after end of destination string
char * StrCpyRetEnd (char *pDest, char *pSrc)
{
while (*pDest++ = *pSrc++);
return pDest;
}
personptr DeepCopyPerson (person *pSrc)
{
personptr pDest = 0;
unsigned int iTotalSize = sizeof(person);
iTotalSize += (strlen(pSrc->name) + 1) * sizeof(char);
iTotalSize += (strlen(pSrc->surname) + 1) * sizeof(char);
iTotalSize += (strlen(pSrc->address1) + 1) * sizeof(char);
pDest = malloc(iTotalSize);
if (pDest) {
#if 1
// alternative one without a helper function
pDest->name = (char *)(pDest + 1); strcpy (pDest->name, pSrc->name);
pDest->surname = pDest->name + strlen(pDest->name) + 1; strcpy (pDest->surname, pSrc->surname);
pDest->address1 = pDest->surname + strlen(pDest->surname) + 1; strcpy (pDest->address1, pSrc->address1);
#else
// alternative two using StrCpyRetEnd () function
pDest->name = (char *)(pDest + 1);
pDest->surname = StrCpyRetEnd (pDest->name, pSrc->name);
pDest->address1 = StrCpyRetEnd (pDest->surname, pSrc->surname);
strcpy (pDest->address1, pSrc->address1);
#endif
}
return pDest;
}
int main(void){
person p1; // programmer managed person with separate mallocs
personptr p2; // created using ClonePerson()
p1.name = malloc(5);
p1.surname = malloc(5);
p1.address1 = malloc(10);
strcpy(p1.name,"AAAA");
strcpy(p1.surname,"BBBB");
strcpy(p1.address1,"address1");
p2 = DeepCopyPerson (&p1);
free(p1.name);
printf("%s\n", p2->name);
free (p2); // frees p2 and all of the memory used by p2
return 0;
}
You have to allocate memory to any pointer if you want to do a copy. However you can always make a pointer point to already allocated memory. For example, you can do the following:
p2.name = p1.name (p1.name is already allocated memory)
This is dangerous as there are more than one reference to the same memory location. If you free either p1.name or p2.name, it results in a dangerous situation.
In order to copy the entire content you have to allocate memory to the pointers of the struct p2.
p2.name = <allocate memory>
Copy individual struct members instead of a memcpy of the entire struct
This is because memory is not allocated in a contiguous manner. Also sizeof(struct) will give you size of the members of the struct and not the memory allocated to it.
For example sizeof(p2) = 8 = sizeof(p1)= sizeof(person) even after allocating memory to members of p1.
It would be a different case had the members been char arrays.
A bit out-of-the-box thinking:
Since the structure of your struct is static, you could write a small utility program or script to generate the copy code for you.
Take the source-code of your struct definition as input, and then devise a set of rules to generate the copying code.
This is quickshot, and I don't know if it were faster to just write the copy-code manually - but at least it is a more interesting problem.

Categories

Resources