C malloc() with structs advice - c

I have two structs and I have an array of 30 pointer StudentType.
I have a problem with malloc(). When I compile it it's ok. But when I try to debug it, it shows "Segmentation Fault" in Dev c++.
In Eclipse, it shows up anything on console. I think that my mistakes are on these lines of code:
students[0]=(StudentType *)malloc(sizeof(StudentType)*NumOfStudents);
(*students[NumOfStudents]).firstName=(char*)malloc(sizeof(char[30]));
(*students[NumOfStudents]).lastName=(char*)malloc(sizeof(char[30]));
That's a part of my code.
#include <stdio.h>
#include <stdlib.h>
typedef struct{
float firstAssignment;
float secondAssignment;
float midterm;
float final;
float finalMark;
}StudentRecordType;
typedef struct{
char *firstName;
char *lastName;
int idNumber;
StudentRecordType marks;
}StudentType;
StudentType *students[30];
char firstName[30];
char lastName[30];
int ReadFromFile();
int PrintAll();
int NumOfStudents;
int i;
int main(void)
{
ReadFromFile();
}
int ReadFromFile()
{
FILE *fp;
fp=fopen("project2-askhsh2.dat","r");
if(fp==NULL)
{
printf("Error opening file.\n");
}
else
{
printf("Successful open of project2-askhsh2.dat\n");
}
fscanf(fp,"%d",&NumOfStudents);
printf("%d\n",NumOfStudents);
students[0]=(StudentType *)malloc(sizeof(StudentType)*NumOfStudents);
(*students[NumOfStudents]).firstName=(char*)malloc(sizeof(char[30]));
(*students[NumOfStudents]).lastName=(char*)malloc(sizeof(char[30]));
for(i=0;i<NumOfStudents;i++)
{
(*students[i]).idNumber=i;
fscanf(fp,"%s %s", (*students[i]).firstName,(*students[i]).lastName);
fscanf(fp,"%f %f %f %f",(*students[i]).marks.firstAssignment,(*students[i]).marks.secondAssignment,(*students[i]).marks.midterm,(*students[i]).marks.final);
printf("%s",(*students[i]).firstName);//, students[i].lastName);
}
}

(*students[NumOfStudents]).firstName=(char)malloc(sizeof(char[30]));
First, the cast is just plain wrong. Casting to char loses information.
Second, in C don't cast the return value from malloc(). It is, at best, redundant, and may hide an error the compiler would have caught without the cast.
If you're going to cast anyway, cast to char*.

You seem to have an extra level of pointers that you don't need causing some confusion, when using the students pointer. You also access past the end of the array that you've allocated.
So instead of
StudentType *students[30];
Which gives you an array of 30 pointers to StudentType I guess you probably just wanted:
StudentType *students;
Which is just a plain pointer to StudentType and can be used as the base of your dynamically allocated array. Then when you do the allocations you'd do this:
students = malloc(sizeof(*students) * NumOfStudents);
And you'd have to initialise each of those StudentTypes before you use them.
for(i=0;i<NumOfStudents;i++)
{
students[i].firstname = malloc(30);
students[i].lastname = malloc(30);
}
Notice that each StudentType is now accessed directly as an element from the students array as student[i], rather than the *students[i] which you had that was wrong. You can expand this to the rest of your code. Remember that you can only access from index 0 to NumOfStudents-1, so do not use students[NumOfStudents].
The other problem you will have is that when you use fscanf() you need to pass the address of the variable to store the result in using the ampersand operator. Currently you are only passing the value, e.g. you should use &students[i].marks.firstAssignment instead of (*students[i]).marks.firstAssignment, assuming you also fix the pointer errors.

These two statements are wrong:
(*students[NumOfStudents]).firstName=(char*)malloc(sizeof(char[30]));
(*students[NumOfStudents]).lastName=(char*)malloc(sizeof(char[30]));
C-arrays are zero-indexed, and so you are trying to dereference one past the size of the array. Assuming that you want to set the first and last name of the last element of students[], then you need to dereference index NumOfStudents - 1.
You don't need to cast the result of malloc() to char * (assuming you are writing a C application).
The sizeof(char) is 1, and so you just need to write malloc(30).

(*students[NumOfStudents]).firstName=(char*)malloc(sizeof(char[30]));
I think you meant:
students[some_index]->firstName = malloc(30);
With some_index something below NumOfStudents.
So your loop becomes:
for(i=0; i < NumOfStudents ; i++)
{
/* students[] is an array of pointers
** students[i] is a pointer
*/
students[ i ] = malloc(sizeof *students[ i ]);
students[ i ]->idNumber=i;
students[ i ]->firstName = malloc(30);
students[ i ]->lastName= malloc(30);
fscanf(fp,"%s %s"
, students[i]->firstName
, students[i]->lastName
);
fscanf(fp,"%f %f %f %f"
, &students[i]->marks.firstAssignment
, &students[i]->marks.secondAssignment
, &students[i]->marks.midterm
, &students[i]->marks.final
);
printf("%s",students[i]->firstName);//, students[i].lastName);
}
And using a global index named "i" can be considered bad style.

Related

I cannot read a structure in another one in c language

I am trying to read a structure which contains another structure and then write it in a binary file. However, when i check if the structure was well read from the keyboard, the structure FIRMA is not read correctly. The value of 'nrang' is always 0 and the 'localitate' string is something very odd.
This is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
char localitate[10];
int nrang;
} FIRMA;
typedef struct
{
char nume[20];
int varsta;
FIRMA firma;
} ANG;
int main()
{
FILE* f;
ANG* a;
int n,i;
if ((f=fopen("fis.txt","wb"))==NULL) exit(1);
printf("number?\n");
scanf("%d",&n);
a=(ANG*)malloc(n*sizeof(ANG*));
printf ("Dati valorile");
for (i=0; i<n; i++)
{
scanf("%s%d",&a[i].nume,&a[i].varsta);
scanf("%s",&a[i].firma.localitate);
scanf("%d",&a[i].firma.nrang);
fwrite(&a[i],sizeof(a[0]),1,f);
printf("%s\n%d\n%s\n%d\n",a[i].nume,a[i].varsta,a[i].firma.localitate,a[i].firma.nrang);
}
}
Note that sizeof(ANG*) is not the same as sizeof(ANG) (the former is the size of the pointer -- probably 8 -- whereas the latter is the size of the structure -- probably 40), which means you're only allocating about 1/5 of the memory you intend to. As a result, the later code winds up writing and reading past the end of what's been allocated, which has undefined behavior.
One practice that helps people with this is to get into the habit of using sizeof(*ptr) when allocating for a pointer ptr, which will always give you the size of what it points to so you don't have to think of "do I need sizeof(ANG) or sizeof(ANG*) here?". This is particularly useful when allocating multi-dimensional arrays (e.g. int ***three_d_array = malloc(n * sizeof(*three_d_array))).

turning file string into char pointer

Hello in first I will give some details, I' m working in:
Ubuntu , in c language and my compiler is gcc.
I was make a lisle test of my skills because I'm not so good with pointers so I tried my luck and I get a weird output.
I will show my code now.
#include<stdio.h>
#include<string.h>
#define F1 ".file.txt"
typedef struct{
char par1[30];
int par2;
int par3;
int par4;
char* par5[3];
}S1;
//this was the structure I was working
void initiate_S1(S1*a,char part1[],int* part2,int *part3, int*part4,char part51[],char part52[],char part53[]);
//this function will start the struct parameters
void get_S1(S1*a);
//this function will print struct parameters
void save_S1_on_file(S1*a);
//this will save all parameters of a structure in file
void search_S1_on_file(S1*a);
//This function will search for a first parameter of structure and if
//find it fill the other parameters
int main(){
S1 a;
int part2,part3,part4;
char part1[30],part51[15],part52[15],part53[15];
scanf("%s %d %d %d %s %s %s",part1,&part2,&part3,&part4,part51,part52,part53);
initiate_S1(&a,part1,&part2,&part3,&part4,part51,part52,part53);
get_S1(&a);
save_S1_on_file(&a);
search_S1_on_file(&a);
get_S1(&a);
return 0;
}
//this main is only to test the functions
void initiate_S1(S1*a,char part1[],int* part2,int *part3, int*part4,char part51[],char part52[],char part53[]){
strcpy(a->par1,part1);
a->par2=*part2;
a->par3=*part3;
a->par4=*part4;
a->par5[0]=part51;
a->par5[1]=part52;
a->par5[2]=part53;
}
void get_S1(S1*a){
printf("%s\n%d\n%d\n%d\n%s %s %s\n",a->par1,a->par2,a->par3,a->par4,a->par5[0],a->par5[1],a->par5[2]);
}
void save_S1_on_file(S1*a){
FILE *af;
af=fopen(F1,"a");
fprintf(af,"%s;%d;%d;%d;%s;%s;%s;\n",a->par1,a->par2,a->par3,a->par4,a->par5[0],a->par5[1],a->par5[2]);
fclose(af);
}
void search_S1_on_file(S1*a){
FILE *af;
char s[100];
char*token;
af=fopen(F1,"r");
int n=2;
while(fgets(s,100,af)!=NULL){
token=strtok(s,";");
if(strstr(a->par1,token)!=NULL){
n=0;
token=strtok(NULL,";");
a->par2=atoi(token);
token=strtok(NULL,";");
a->par3=atoi(token);
token=strtok(NULL,";");
a->par4=atoi(token);
a->par5[0]=strtok(NULL,";");
a->par5[1]=strtok(NULL,";");
a->par5[2]=strtok(NULL,";");
break;
}
else
n=1;
}
if(n==1)
printf("The S1 no exist\n");
}
input:
name 15 3 2 tag1 tag2 tag3
output:
name
15
3
2
tag1 tag2 tag3
name
15
3
2
%��j��2 j��2 tag3
For some reason when I try fill the char pointers from file string appears this weir output
why appear this weird chars and whats is wrong in my code?
You are good until you call search_S1_on_file()
Inside this for the array of pointers a->par5 you assign the address of the local variable s.
a->par5[0]=strtok(NULL,";");/* The string being broken into tokens is a local array */
a->par5[1]=strtok(NULL,";");
a->par5[2]=strtok(NULL,";");
Once you exit this function the memory allocated for the array s is freed so accessing this memory location you are bound to get garbage values because this is UB.
In order to fix this keep a char array in main and pass it to the function search_S1_on_file() along with other requierd parameters and that should work.
Alternatively you can try allocating memory on heap for the array s like
char *s = malloc(100); /* Take care to free this memory accordingly */

Array of struct implementation in C

I need some ideas on my array of struct implementation. This is what I have in my structs. I plan on making SHAPES an array because I will have multiple SHAPES. Each shape will have multiple x and y coordinates. Because of this I'm not sure if should make a linked list or not. The purpose of the start and finish is I will eventually be running a search algorithm after I get my shapes right.
struct START
{
int x;
int y;
};
struct END
{
int x;
int y;
};
struct SHAPES
{
int x [100];
int y [100];
int *link;
};
struct DISTANCE
{
int distance_traveled;
int distance_to_finish;
};
I was reading this and was wondering if I needed to malloc or calloc my structs as I create them. If so why and if not why? Malloc and calloc are always confusing to me.
How do you make an array of structs in C?
int main(int argc, char *argv[])
{
//Is it better to make these pointers?
struct START start;
struct END end;
struct SHAPES shapes[100];
while(fgets(line, 80, fp) != NULL)
{
//I have a very annoying issue here, I don't know the size of the lines.
//If there are more values I want to increment the x[] and y[] array but NOT the
//shapes array. I can only think of one way to deal with this by putting a bunch of
//variables in the sscanf. I discovered putting sscanf on the next line didn't do what
//I was hoping for.
sscanf(line, "%d%*c %d%*c ", &shapes[i].x[i] , &shapes[i].y[i] );
printf(" line is: %s \n", line);
sscanf(line, "%d%*c %d%*c ", &x1_main , &y1_main );
printf(" line is: %s \n", line);
printf(" shapes[i].x[i] is: %d \n", shapes[i].x[i]);
printf(" shapes[i].y[i] is: %d \n", shapes[i].y[i]);
printf(" x1_main is: %d \n", x1_main);
printf(" y1_main is: %d \n", y1_main);
i++;
memset(line, 0, 80);
}
}
This is what my file looks like. Adding the %*c seemed to handle the commas and semicolons appropriately.
10, 4
22, 37
22, 8; 2, 0; 3, 6; 7, 8; 5, 10; 25, 2
1, 2
I got that idea from here.
https://www.daniweb.com/software-development/c/threads/334515/reading-comma-separated-values-with-fscanf
First of all, you might want to consider something like this:
struct point {
int x;
int y;
};
so you can use a struct point data structure (array) instead of two separate data structures for x and y. Using it like this should also speed up access to the points, since their coordinates are next to each other in memory. Otherwise you will have x somewhere in the x array and y somewhere in the y array.
The choice of the data structure to store the points depends on your usage. If you need to address points directly, a linked list may be a bad choice. If you always access all points in a linear order, it is fine. However, consider that a singly linked list will add 8 bytes per point for the next pointer. A doubly linked list will use another 8 bytes for prev (assuming 64-bit arch that is; sizeof(pointer) in general). I assume, that you create x[100] and y[100] to make sure you have enough space. You might be better off using a dynamic array (the ADT) e.g. glib's GArray after all. It will grow as big as you need it without you doing anything.
For malloc vs calloc: it doesn't really matter. A call to calloc is basically a malloc followed by a
memset(ptr, 0, sizeof(mallocd area);
i.e. the memory is zeroed; cf manpage calloc. If you initialize the memory directly you may not need to do this.
A struct with no pointer members
If your struct has no pointer members, such as:
typedef struct {
int a;
int b;
} DEMO;
Then you can simply declare an array instance of a typedef struct like this:
DEMO demo[10];// instance of array of 10 DEMO
Example, struct with Pointer members
If you have a pointer in the list of members:
#define SIZE_STR 20
typedef struct {
int a;
int b;
char *str;//pointer, will require memory allocation
} DEMO;
DEMO demo[10];// instance of array of 10 DEMO
int main(void)
{
int i;
for(i=0;i<10;i++)//create memory for each instance of char * in array of DEMO
{
demo[i].str = malloc(SIZE_STR);
}
return 0;
}
Don't forget to free() all instances of malloc'ed memory.
Dynamically allocate array of struct
If you need to dynamically allocate memory for a struct:
typedef struct {
int a;
int b;
} DEMO;
DEMO demo, *pDemo;// create a pointer to DEMO
In a function, main() for example:
int main(void)
{
pDemo = &demo;
pDemo = malloc(sizeof(DEMO)*10);//provides an array of 10 DEMO
return 0;
}
Again, don't forget to free() all instances of malloc'ed memory.

Changing values in elements of an array of structs

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;
}

C structures, memory alloc and structures

So, the task is to read file and push data to structure. the data file is:
babe 12 red 12
deas 12 blue 12
dsa 12 red 512
bxvx 15 blue 52
reed 18 black 15
while code is something like that
struct shoes {
char name[8];
int size;
char color[8];
int price;
};
//open file
shoes *item=(struct shoes*)malloc(sizeof(struct shoes));
for (i=0; !feof(file); i++) {
item=(struct shoes*)realloc(item,sizeof(struct shoes)+i*sizeof(struct shoes));
fscanf(file,"%s %i %s %i\n",(item+i)->name,(item+i)->size,(item+i)->color,(item+i)->price);
}
but the program crashes every time.
dbg says: No symbol "item" in current context.
where is error?
You code has some bugs:
1) You need a typedef for shoes unless you're compiling with a C++ compiler ... but then you should have tagged this C++.
2) feof doesn't return false until an attempt has actually been made to read beyond the end of file, so your code makes the array of shoes 1 too large.
3) You're passing ints to fscanf instead their addresses.
If compiling as C code, not C++ code, the casts on malloc and realloc aren't necessary and are advised against. And there are other stylistic issues that make you code harder to comprehend than it could be. Try this:
typedef struct {
char name[8];
int size;
char color[8];
int price;
} Shoe;
// [open file]
Shoe* shoes = NULL; // list of Shoes
Shoe shoe; // temp for reading
for (i = 0; fscanf(file,"%s %i %s %i\n", shoe.name, &shoe.size, shoe.color, &shoe.price) == 4; i++)
{
shoes = realloc(shoes, (i+1) * sizeof *shoes);
if (!shoes) ReportOutOfMemoryAndDie();
shoes[i] = shoe;
}
The problem is that you are not passing pointers to the integers you want to read using fscanf, you are passing the integers themselves.
fscanf treats them as pointers. And where do they point? Who knows - the integers were uninitialized, so they could point ANYWHERE. Therefore, CRASH.
Fix thusly:
fscanf(file,"%s %i %s %i\n",
(item+i)->name,
&((item+i)->size),
(item+i)->color,
&((item+i)->price));
Note that you don't need the same for name and color because arrays degenerate to pointers, so you're passing the right thing already.
And please, consider ditching the item+i notation; item[i] is so much clearer and easier to understand when casually reading the code:
fscanf("%s %i %s %i\n",
item[i].name,
&item[i].size,
item[i].color,
&item[i].price);
Are you sure the debugger says that? I'm surprised it even compiled...
You wanted:
struct shoes *item
If you don't proved a typedef of your structure, you have to explicitly say "struct" every time you reference it.
Second note:
item=(struct shoes*)realloc(item...
Don't assign the same pointer from realloc() that you pass into it. If the reallocation fails it will return NULL and that could be killing you. You should make sure you're checking the results of both the initial malloc() and the realloc()
Third point:
You need to be passing the address of the int's to the fscanf().
fscanf(file,"%s %i %s %i\n",(item+i)->name,&((item+i)->size),(item+i)->color,&((item+i)->price));
There are two issues with your code:
1st. The struct:
you could define your struct in two ways,
the way you did:
struct shoe{
char name[8];
int size;
char color[8];
int price;
};
and in this case you should refer to a pointer to it as:
struct shoe *item;
the other (perhaps more convenient?) way using a typedef along with the defenition:
typedef struct {
char name[8];
int size;
char color[8];
int price;
} shoe;
and in this case you should refer to a pointer to it as:
shoe *item;
Therefore the code you posted isn't supposed to compile.
2nd one:
fscanf should be given pointers to integers/chars in the case you showed.
You've correctly passed the char pointer(since you passed the name of a char array which is actually a char pointer to the first element), but you have passed some integers and fscanf needs pointer to integers it is supposed to fill, so your code should be:
fscanf(file,"%s %i %s %i\n",(item+i)->name,&((item+i)->size),(item+i)->color,&((item+i)->price));

Resources