Create an element of a struct array using struct pointer function - c

I have been trying to write a function with a pointer point to a struct array. After calling it my array should have a new struct element.
This is my function changed by ur guys suggestion
void addPic(pic *picture_Record, int picNumber){
pic tmp_Pic;
char tmp_fileName[100];
char tmp_description[100];
char tmp_location[100];
if (picture_Record[picNumber].description ==NULL || picture_Record[picNumber].fileName ==NULL||picture_Record[picNumber].location==NULL)
return;
printf("Enter: Picture Name, Picture Description, Picture Location, Picture People(int)\n");
scanf("%s%s%s%d",tmp_fileName, tmp_description, tmp_location, &picture_Record[picNumber].peopleCount);
tmp_Pic.fileName = (char*)malloc(strlen(tmp_fileName)+1);
tmp_Pic.description=(char*)malloc(strlen(tmp_description)+1);
tmp_Pic.location = (char*)malloc(strlen(tmp_location)+1);
strcpy(tmp_Pic.fileName, tmp_fileName);
strcpy(tmp_Pic.description, tmp_description);
strcpy(tmp_Pic.location, tmp_location);
picture_Record[picNumber] = tmp_Pic;
free(tmp_Pic.fileName);
free(tmp_Pic.description);
free(tmp_Pic.location);
printf("\nInput Done!\n");
This is how I call it.
int picNumber = 0
pic pictureRecord[Maximun_Picture +1]= { "" };
addPic(&pictureRecord[picNumber], picNumber);
picNumber++;
//testing
printf("%s",pictureRecord[0].location)
This is my struct.
typedef struct picture_Data
{
char* fileName;
char* description;
char* location;
int peopleCount;
}pic;
It doesn‘t work and printing me Null as th location of the first element. Why? Can somebody help me.

The problem is that this line
scanf("%s%s%s%d",pic_tmp.fileName, pic_tmp.description, pic_tmp.location, &pic_tmp.peopleCount);
assumes that pic.tmp has sufficient space allocated for fileName, description, and location. None of that is true, however, because all three fields remain uninitialized.
In order to fix this, change the code to read strings into a temporary buffer, and then copy it into dynamically allocated strings.
Here is how you do it for fileName; you need to do the same thing for all three:
char tmp_fileName[100];
char tmp_description[100];
char tmp_location[100];
scanf("%99s%99s%99s%d",tmp_fileName, tmp_description, tmp_location, &pic_tmp.peopleCount);
pic_tmp.fileName = malloc(strlen(tmp_fileName)+1);
strcpy(pic_tmp.fileName, tmp_fileName);
...
You can copy the struct with a single assignment, too:
picture_Record[picNumber] = pic_tmp;
Don't forget to call free on all three members of each struct to avoid memory leaks.

You should first have to allocate memory
void addPic(pic *picture_Record, int picNumber){
pic pic_tmp;
printf("Enter: Picture Name, Picture Description, Picture Location, Picture
People(int)\n");
pic_tmp.fileName = (char *)malloc(5);
picture_Record[picNumber].fileName = (char *)malloc(5);
scanf("%s%d",pic_tmp.fileName, &pic_tmp.peopleCount);
printf("\nInput Done!\n");
strcpy(picture_Record[picNumber].fileName, pic_tmp.fileName);
//picture_Record[picNumber].fileName = pic_tmp.fileName;
picture_Record[picNumber].description= pic_tmp.description;
picture_Record[picNumber].location = pic_tmp.location;
picture_Record[picNumber].peopleCount = pic_tmp.peopleCount;
printf("%s,%s",pic_tmp.fileName,picture_Record[picNumber].fileName );
}

Related

char* value changing after use of fgets

so my first question would be. Does fgets overwrite other char* values?
Otherwise, I'm not really sure how I have messed up my mallocs. Below is the code where the value is changing. First line is where the variable is being created.
data[dataIndex++] = createVariable(varName, 1, value, -1, line, NULL);
The code where the variable is being created
Variable *createVariable(char *name, int type, int val, int len, int line, char *string)
{
Variable *var = malloc(sizeof(Variable));
var->name = name;
var->setting = type;
var->num = val;
var->length = len;
var->line = line;
var->string = string;
return var;
}
What data looks like and how it was created.
Variable **data;
data = malloc(4 * sizeof(Variable *));
Forgot to add this, but below is my fgets code
if (fgets(line, MAX_LINE_LENGTH, in) == NULL)
{
break;
}
The problem is this line in your createVariable function:
var->name = name;
What this does is copy the pointer given as the first argument to the name field in the var structure; it doesn't make a (separate) copy of the data that is pointed to! So, assuming you call createVariable many times with the same variable as the first argument, then every object created will have the same address in its name field, and any modifications you make to any of them (via fgets) will change all of them.
To get round this, you need to allocate new memory for the name field, each time you call the createVariable function, then copy the string data to it. The simplest way to do this is using the strdup function:
Variable *createVariable(char *name, int type, int val, int len, int line, char *string)
{
Variable *var = malloc(sizeof(Variable));
var->name = strdup(name);
//...
var->string = strdup(string);
//...
But note, you will now need to be sure to free that memory from each object when you (eventually) delete it. Something like this:
void deleteVariable(Variable** var)
{
free((*var)->name); // free the name memory
free((*var)->string); // free the string memory
free(*var); // free the actual structure
*var = NULL; // set the pointer to NULL - to prevent multiple frees
}
EDIT: Just re-read your question, and noticed that you are making the same mistake with the string field! The same fix needs to be applied to that!

Saving input text to struct in main

got a question how to save a struct to an array and print it out in main().
My idea is, to get data of a .txt and then save it in a struct array. If i output it directly with printf() it works fine.
But if I want to save it in a struct array and print it out at themain() I get trash values, nothing or just the last read struct will be saved to all positions of the array.
My code looks like this:
typedef struct CAR {
char* nickname;
char* model;
} CAR;
void getInputFromFile(struct CAR *arr) {
. . .
. . .
char *nickname = malloc(...);
char *model = malloc(...);
int i=0;
while(fscanf(file,"%s %s\n", model, nickname)==2){
printf("%s %s\n", model, nickname); // this works fine!!!
// Now when i try to save it in a struct it doesn't work
arr[i]->model = model;
arr[i]->nickname = nickname;
i++;
}
free(nickname);
free(model);
}
int main (){
struct CAR* arr[size];
getInput(arr);
// Now iterate over arr to look at values
for(i = 0; i < size; i++){
...
}
}
File input format looks like this:
nickname model\n
nickname model\n
...
Thanks for all your help in advance!
you must duplicate (strdup) each string before to put it in your structure
arr[i]->model = strdup(model);
arr[i]->nickname = strdup(nickname);
currently all ar[]->model point to the same memory area, and that one was freed, same thing for all arr[]->nickname
in your program you forget also to allocate each CAR, so in fact :
arr[i] = (CAR *) malloc(sizeof(CAR));
arr[i]->model = strdup(model);
arr[i]->nickname = strdup(nickname);
Each struct needs allocated memory for the strings. Currently you have a single string buffer for nickname and model (so its being overwritten) and free it at the end of the loop, so now each struct is pointing to freed memory, not the original strings.

failed while trying to reach pointer in struct

my project is to build book structure - and fill it with users parameters.
involving dynamic allocation, arrays and pointers.
my book structure has the following:
struct BOOK
{
char* author;
char** genders;
int totalGenders;
char* name;
int* chapterPages;
int totalChapters;
}typedef book;
when I tried reaching author name, line 1 in structure:
struct BOOK
{
char* author;
I failed doing that.. my code in main :
int main()
{
book* b;
char authorChar[10] = { 0 };
int authorLen;
char* authorName;
// get author name
puts("please enter the name of the author");
scanf("%s", &authorChar);
authorLen = strlen(authorChar);
printf("%d", authorLen); //print to see that lentgh is correct.
authorName = (char*)calloc(authorLen, sizeof(char));
strcpy(authorName, authorChar);
puts("\n");
b->author = authorName;
printf("%d", b->author);
when i have debugged i got a problem in this line :
b->author = authorName;
ideas please? :)
The problem is in the following line
b->author = authorName;
at this point, b is not allocated memory, i.e., b is an uninitialized pointer. It points to some random memory location which is not a valid one. Any attempt to access invalid memory invokes undefined behavior.
You can use either of the following approach to resolve the issue:
allocate memory to b dynamically before using it, like b = malloc(sizeof*b); and a check for success.
define b as a variable of type book, instead of a pointer-to-type.
That said, int main() should be int main(void) at least, to conform to the standards.
You are forgetting to do the memory allocation for b variable.
b = malloc(sizeof(book));
b->author = malloc(sizeof(100000)); // replace value for the size you want

Reused Address Space in C?

In a part of the program I'm working on I assign a name differently in different circumstances, but I want to keep the name either way, obviously. So I did something like so:
char *name;
if(*condition one*){
char namebuilder[30] = "";
//fill char array here
name = namebuilder;
} else {
name = info->name; //a char* from a struct
}
char otherstring[30] = "______________________________"
So basically the problem I'm having is that when the function takes the else route name sticks around and works just fine. But when it makes namebuilder and constructs the name, for some reason otherstring is ending up in the same address as name, and the name is getting overwritten with "__________________________". I don't understand why this is happening or how I can prevent it.
P.S: I've tested it by printing the addresses of name and otherstring, and they have the same address stored in them, but only if namebuilder was used.
Extra Background: this is a little program I'm making to mess around with pthreads, so it could possibly have to do with threading I guess, but none of the variables I mentioned are global.
EDIT: Here's the actual code for those of you asking.
struct thread_data
{
char *name;
int max;
};
void* race(void* params)
{
struct thread_data* info;
info = (struct thread_data*)params;
int len = strlen(info->name);
char* name;
if(info->max > len){
int i;
char newname[30] = "";
for(i = 0; i < info->max-1; i++){
if(i < len){
newname[i] = info->name[i];
} else {
char nextchar = randChar();
newname[i] = nextchar;
}
}
newname[info->max] = '\0';
name = newname;
} else {
name = info->name;
}
pthread_mutex_lock(&locker);
printf(name); //This correctly prints the name either way.
printf(" takes off!\n");
pthread_mutex_unlock(&locker);
//begin trying to spell here.
int spelt = 0;
char spelling[30] = "______________________________";
// All code after this sees name as "______________________________" only if it came
// from the if statement and not the else.
namebuilder was stored in the stack because it's local inside the if statement, after exiting the condition, it was marked as free, so when declaring otherstring, which have the exact same type and memory use as namebuilder, it took its place in the stack.
Here's how you can fix it:
char *name;
char namebuilder[30] = "";
if(*condition one*){
//fill char array here
name = namebuilder;
} else {
name = info->name; //a char* from a struct
}
char otherstring[30] = "______________________________";
Namebuilder is local to the if block. You need to lift it one scope up, or allocate it in dynamic memory with malloc() (don't forget to free() it when you're done !)
Your namebuilder is local to the if block. Which means that once you leave that and try to use your name, accessing the memory name points at now is UB. You'll either have to dynamically allocate the memory for namebuilder - which means you'd have to remember to clean it up later on - or you'd have to lift the declaration of namebuilder to the scope where it's being used.

How to properly malloc for array of struct in C

I will read in two set of char* (or strings) using strtok, and since those two set of chars are related, (address : command\n) I decided to use a structure.
struct line* array = (struct line*)malloc(sizeof(file) * sizeof(struct line*));
This line mallocing space for the function gives me a segmentation fault and was wondering if you can tell me a proper way to malloc space for it. For context, here is the rest of my code:
struct line
{
char* addr;
char* inst;
};
while loop{
x = strtok(line,": ");
y = strtok(NULL,"\n");
strcpy(array[i].addr,x); //assume that x and y are always 3characters
strcpy(array[i].inst,++y);
i++;
}
Allocating works the same for all types. If you need to allocate an array of line structs, you do that with:
struct line* array = malloc(number_of_elements * sizeof(struct line));
In your code, you were allocating an array that had the appropriate size for line pointers, not for line structs. Also note that there is no reason to cast the return value of malloc().
Note that's it's better style to use:
sizeof(*array)
instead of:
sizeof(struct line)
The reason for this is that the allocation will still work as intended in case you change the type of array. In this case this is unlikely, but it's just a general thing worth getting used to.
Also note that it's possible to avoid having to repeat the word struct over and over again, by typedefing the struct:
typedef struct line
{
char* addr;
char* inst;
} line;
You can then just do:
line* array = malloc(number_of_elements * sizeof(*array));
Of course don't forget to also allocate memory for array.addr and array.inst.
For what you have described, You do not need to allocate memory for your struct, rather, you need to allocate memory for the members char *addr;, and char *inst;. If you want to have a single copy of that structure, the first section of code illustrates how to initialize, and assign values. If you want an array, the second code example illustrates the differences.
This illustrates how to allocate memory for the members of a single struct line:
typedef struct
{
char* addr;
char* inst;
}LINE;
LINE line;
int main(void)
{
strcpy(line.addr, "anystring"); //will fail
line.addr = malloc(80);
line.inst = malloc(80);
strcpy(line.addr, "someString");//success;
strcpy(line.inst, "someOtherString");//success;
}
For array of struct line...
typedef struct
{
char* addr;
char* inst;
}LINE; //same struct definition
LINE line[10]; //but create an array of line here.
int main(void)
{
int i;
for(i=0;i<10;i++)
{
line[i].addr = malloc(80);
line[i].inst = malloc(80);
}
for(i=0;i<10;i++)
{
strcpy(line[i].addr, "someString");
strcpy(line[i].inst, "someOtherString");
}
//when done, free memory
for(i=0;i<10;i++)
{
free(line[i].addr);
free(line[i].inst);
}
}
Added to address comment
Addressing the comment under this answer from #Adam Liss, the following code illustrates the following improvements using strdup(): 1) Uses only memory needed. 2) Performs memory creation and copy operations in one step, so the the following blocks:
for(i=0;i<10;i++)
{
line[i].addr = malloc(80);
line[i].inst = malloc(80);
}
for(i=0;i<10;i++)
{
strcpy(line[i].addr, "someString");
strcpy(line[i].inst, "someOtherString");
}
Become:
for(i=0;i<10;i++)
{
line[i].addr = strdup("someString");
line[i].inst = strdup("someOtherString");
}
One more note: Error handling was not included in examples above to avoid muddling up focus on the main concepts: But for the sake of completeness, because both malloc() and strdup() can fail, actual usage for each of these two functions, should include a test before using, eg:
Rather than
line[i].addr = strdup("someString");
line[i].inst = strdup("someOtherString");
The code should include
line[i].addr = strdup("someString");
if(!line[i].addr)
{
//error handling code here
}
line[i].inst = strdup("someOtherString");
if(!line[i].inst)
{
//error handling code here
}

Resources