I cannot read a structure in another one in c language - c

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))).

Related

How should I properly malloc an array of struct?

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <tchar.h>
#include <string.h>
#include <math.h>
HANDLE wHnd; // Handle to write to the console.
HANDLE rHnd; // Handle to read from the console.
struct Terra {
int status;
CHAR_INFO display;
};
int main(){
int countX = 0;
int countY = 0;
int total = 0;
CHAR_INFO ScreenCon[10000];
int localcount = 0;
struct Terra *world= malloc(10000*sizeof(*world));
...
I have been using visual studio programing a screen console program that generate and display an 100 x 100 CHAR_INFO array. without using malloc(). My code is referenced from Ben Ryves' windows console tutorial.
The code without malloc() function is:
struct Terra world[100][100];
This code works perfectly but the compiler warns me that I should allocate memory for it. So I tried to integrated memory allocation in it and I learned that malloc() can't allocate 2d array directly, I can only do so by dividing my chunk of memory into 100 parts and use 1 extra array to store their location, my solution is to revert that 2d array into 1d and handle the data location with extra code. However, with reference to other question in stack overflow, I have change my code to the one above. But I got error code E0144 and C2440 at line 28, what have I done wrong?
Isn't that code is supposed to created a new pointer of struct Terra who called world then allocate 10000 x the size of single Terra is for it? How should I initialize an pointer before its declared??
I have read some information about malloc() but seem I don't understand how this really work. I would like to know what I have done wrong.
P.S.: I have done more tests and it seems the problem is that malloc() statement:
struct Terra {
int status;
CHAR_INFO display;
};
int main()
{
struct Terra* world = malloc(10000 * sizeof(*world));
return 0;
}
This code also returns the same error.
So, you want to have the equivalent of struct Terra world[100][100];, but allocated with malloc rather than having it on the stack, right?
I assume you know that you can allocate hundred objects of type foo like this:
foo *bar = malloc(100* sizeof(*bar));
bar is now a pointer to the first element of an array of 100 foo.
So in the world 2d array above you have an array of arrays of struct Terra of length 100. Basically, foo is an array of 100 struct world:
typedef struct Terra foo[100];
You can now allocate 100 of those arrays:
foo *world = malloc(100* sizeof(*world));
World now points to the first array of 100 struct Terra of 100 such arrays
Naturally, this can be done without a typedef:
struct Terra (*world)[100] = malloc(100* sizeof(*world));
I know this text may be a confusing mess of "arrays of arrays" but I hope you get the point.
Just an added comment on using malloc. When doing allocations like this: malloc(count * sizeof(*something)), be sure to make sure that the multiplication doesn't overflow. One of the biggest security bugs in the java virtual machine, was a failure to do such a check.
Correct/Valid solution:
If you want to access/iterate the 2D array like it got declared like struct Terra world[100][100];
Then you can alloc 100 diferent arrays, like this, and
struct Terra **world= malloc(100*sizeof(Terra*));
for(int i=0; i<100;i++){
world[i] = malloc(100*sizeof(Terra));
}
//the "usual" way to access the indexes
for(int i=0; i<100;i++)
for(int j=0; j<100;j++)
printf("%d ", world[i][j].status);
But if you want to use a singles continuous chunk o memory, you must allocate it like a 1D array, and access it doing some simple math:
size_t total_size = 100*100 //100 and 100 are the dimensions
struct Terra *world= malloc(total_size*sizeof(Terra));
//this way to access the indexes
for(int i=0; i<100;i++){
for(int j=0; j<100;j++){
//the formula to convert 2D indexes to a 1D array is: (i*N)+j, where N = number_of_columns
printf("%d ", world[i*100 + j].status);
}
}
wrong old answer
struct Terra **world= malloc(100*100*sizeof(Terra));

Writing struct containing dynamic array to binary file (C)

I'm writing a program that writes arrays and the information regarding them to a binary file.
My first approach was to call fwrite 4 times: once for general information regarding the array, once for the timestamp, once for the dimension of the array and once to write the array itself.
This approach worked as it is quite simple, but the execution times were too slow, seeing as the program is multithreaded and it writes to a SAS drive frequently, flooding the drive with requests which presented a bottleneck.
The new approach was to create an array of structs containing the information needed, my struct would be as follows:
struct array_data{
int information;
int timestamp;
int size;
int* data_array;
}
During execution I would write the data to a buffer and when I had everything I need it would call a malloc to allocate array_data.data_array and copy everything from the buffer from inside a for loop.
The issue is when I call fwrite to write the whole struct, the first 3 members of the struct are written correctly, while the array is not and that is due to the address of the array not being contiguous, since it points to another place in memory after the malloc.
The best solution to this would be to declare the data_array as a static array, this way the fwrite would work as I need it to, but then I would have to call fwrite for every struct, instead of calling it once to write an array of structs, which would impact the performance, negating the use of the struct.
I've also tried using an array of dynamically allocated structs, by declaring my struct as follows:
struct array_data{
int information;
int timestamp;
int size;
int data_array[];
}
and allocating the array of structs using malloc, but the address of struct_array[1].information is not the one right after the struct_array[0].data_array[last_index], there seems to be another 5 bytes in between, so if I were to call fwrite with struct_array the data in the file would still be incorrect.
Is there a way to use structs to solve this issue or should I just stick with writing my arrays to the file as I did in the first place?
The following example creates, writes and reads your data. It is just a outline. Error checks on malloc, fread and fwrite ommitted:
#define N_DATA 10
#define N_INTS 5
struct array_data{
int information;
int timestamp;
int size;
int* data_array;
};
struct array_data arr[N_DATA];
void makeData(void){
int i;
for (i=0;i<N_DATA;i++) {
arr[i].data_array=malloc(N_INTS*sizeof(int));
arr[i].size= N_INTS;
}
}
void writeData(FILE *fp_out)
{
int i;
for (i=0;i<N_DATA;i++) {
fwrite(&arr[i],sizeof(arr[i]),1,fp_out);
fwrite(arr[i].data_array,arr[i].size*sizeof(int),1,fp_out);
}
}
void readData(FILE *fp_in)
{
int i= 0;
while(fread(&arr[i],sizeof(arr[i]),1,fp_in)==1) {
arr[i].data_array=malloc(arr[i].size*sizeof(int));
fread(arr[i].data_array,arr[i].size*sizeof(int),1,fp_in);
i++;
}
}

issue when ordering an array of structs in C

I want to order an array of structs by the first letter of a studentĀ“s name. The code that I made so far is the following:
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int cod;
char* name;
int mark;
}student;
void print(student* class){
int i;
for (i=0;i<4;i++){
printf("%d\n",class[i].cod);
printf("%s\n",class[i].name);
printf("%d\n",class[i].mark);
printf("\n");
}
}
int main(int argc, char *argv[])
{
int ind,i;
int cod=1000;
student class[4];
student temp;
int lengthData=10;
for (i=0;i<4;i++)
{
class[i].name=malloc(sizeof(char)*lengthData);
}
class[0].cod=cod;
class[0].name="Joseph";
class[0].mark=15;
cod++;
class[1].cod=cod;
class[1].name="Jonathan";
class[1].mark=16;
cod++;
class[2].cod=cod;
class[2].name="Karen";
class[2].mark=17;
cod++;
class[3].cod=cod;
class[3].name="Anna";
class[3].mark=20;
print(class);
for (ind=1;ind<4;ind++){
temp=class[ind];
i=ind-1;
while (i>=0){
if (temp.name[0]<class[i].name[0]){
class[i+1]=class[i];
class[i]=temp;
i--;
}
else break;
}
}
printf("ordered data\n");
print(class);
system("PAUSE");
return 0;
}
I am using DevC++ and when I run it the program hangs, but when I add the following lines before the loop for the bubble sort (only for testing):
class[3]=class[2];
printf("%s\n",class[3].name);
for (ind=1;ind<4;ind++){
...
The program works even though one record (3) has been replaced by the data of record (2).
Any help?
You have quite a few problems:
First of all you leak memory, since you allocate memory and make name point to that, then you make name point somewhere else. You need to copyinto the memory you allocate.
Secondly, also with the name member, once you copy into the memory, you will go out of bounds since you only allocate five bytes for each string, but you have strings of up to at least nine characters (ten with the terminator).
Thirdly, and more about going out of bounds, your class array only have three elements, yet you access four elements of the array.
The reassignment of the name pointer won't cause more problems than a temporary memory leak, since you don't attempt to pass the pointer to free. The second problem isn't really an issue because you don't copy the strings yet. The third problem on the other hand, that will lead to undefined behavior as soon as you execute that code.

Structures used to store postal codes

It asks me to create a hash function that turns the postal code into an integer by summing its characters. This is my code. I haven't got to the hash function yet.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct PostalCode
{
int size;
char *array[6];
} PostalCode;
int main()
{
int size = 6, i;
PostalCode *h = malloc(sizeof(PostalCode));
h->size = size;
h->array = malloc(sizeof(char)*size);
printf("Please enter your postal code: \n");
for (i=0; i<6; i++)
scanf(" %c", &(h->array[i]));
}
And the errors I get now are: postalcode.c:9:11: error: assignment to expression with array type
h->array = malloc(sizeof(char)*size);
The line
char *array[6]
declares an array of 6 pointers to char, and that's not what you want here. You can just make it
char * array
and resolve the error that way, or follow chux's advice, i.e. have
char array[6]
in which case you don't need the line that's causing the error, just remove it. No need to dynamically allocate the array.
A few other suggestions:
If your postal code is always 6 characters, then you don't really
need the PostalCode structure, unless you plan on keeping some other
information about the postal code there. You could just do
typedef char PostalCode[6];
Of course, if you expect postal codes to have
variable length, then size might help.
Regardless of whether you want a struct or typedef a char array, hard-coding the value 6 is a bad idea. If it's always 6 characters, then you can #define it; or if you keep the size in the structure, then make sure you initialize it and use the struct member instead of the literal number 6.
There is no need to dynamically allocate memory here, but if you do make sure you free it.
Good luck!

C malloc() with structs advice

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.

Resources