issue when ordering an array of structs in C - 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.

Related

2D dynamic array in c - accessing allocated variable

I'm struggling (again..) with a project in C coding.
Please help me to understand how to access a variable that was dynamically allocated, through 2D array that was also dynamically allocated.
Every attempt ends up with failure, and I can't find the right syntax...
The attempt : putting a string in the family_name pointer in the new Family allocated into **list.
scanf(" %s",&lod->list[0]->family_name);
The program:
#define _CRT_SECURE_NO_WARNINGS
//Libraries
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//Consts, globals, structs
#define MAX 10000
typedef struct person
{
char *name;
int gender; //1-female, 0-male
} Person;
typedef struct family
{
char *family_name;
Person *mother, *father; // parents' names
Person **children_list; // list of the children in this family
unsigned child_list_size; // size of child_list array
unsigned current_listChild_size;
} Family;
typedef struct listFamilys
{
Family **list;
unsigned current_listFamily_size; // current size of family
}
ListFamilys;
//main
void main()
{
ListFamilys *lod = (ListFamilys*) malloc(sizeof(ListFamilys));
if(! lod) exit(0);
lod->current_listFamily_size =0;
lod->list = (Family**)malloc(sizeof(Family*));
if (!lod->list) exit(0);
printf("Enter family name: ");
**scanf(" %s",&lod->list[0]->family_name);**
system("pause");
}
The issue here is simply a type error combined with insufficient allocation. In order for this to work you need to allocate space for some Family pointers (which you are doing, though only 1), and then an actual Family element (which you are not doing) and then allocate space for the name (which you are not doing). Basically, the code should be
lod->list = (Family**) malloc(sizeof(Family*));
lod->list[0] = (Family*) malloc(sizeof(Family));
lod->list[0]->family_name = (char*) calloc(11, 1);
where you are only doing the first line of that. My usage of calloc here is somewhat arbitrary, as is the 10 char limit. You can modify as is appropriate.
However, while this is the simplest way to get a single element up and running, this approach collapses at the large scale because of how many allocations you have to do, and deallocating memory becomes a nightmare due to how many separate allocations are made using this approach. Therefore, it is better to allocate say 4kb of space for names to a separate pointer, and then point the name field of persons and families to the relevant name rather than a separate allocation for each of their names. So on with the rest of it. Essentially, try to extract allocations rather than tunnel down with them field after field like the code above does.

managing memory in a for loop

I am trying to save information from a file to structs in the heap.
The problem is: if i print out the information in the for loop where i save the data, it works well, but when i print out the data outside that for loop i get only garbage
i wanna know why :( probably i am doing a bad work with the malloc
i could work inside the first for loop but i want to know what i am doing wrong
typedef struct{
int tipoDeCodificacion;
void* carta;
}pedido;
typedef struct{
void* nombre;
void* regalo;
}regalos;
void creacionRegalos(FILE *cartas){
FILE *final=fopen("regalos.txt","w");
int cantidadCartas, i;
fscanf(cartas,"%d\n",&cantidadCartas);
printf("%d\n",cantidadCartas);
pedido *Pedidos=(pedido *)malloc(sizeof(cantidadCartas));
regalos **Regalos=malloc(sizeof(regalos *)*cantidadCartas);
for(i=0;i<cantidadCartas;i++){
char *lineaCodificada=malloc(sizeof(char)*100);
int *tipo=malloc(sizeof(int));
fscanf(cartas,"%d\n",tipo);
Pedidos[i].tipoDeCodificacion=*tipo;
printf("%d\n",Pedidos[i].tipoDeCodificacion); //this print works well
fgets(lineaCodificada,100,cartas);
Pedidos[i].carta=lineaCodificada;
puts(Pedidos[i].carta); //this print works well
}
for (i = 0; i < cantidadCartas; i++) {
printf("%d\n",Pedidos[i].tipoDeCodificacion); //just prints garbage
printf("%s\n",(char *)Pedidos[i].carta);//prints garbage
}
}
The line:
pedido *Pedidos=(pedido *)malloc(sizeof(cantidadCartas));
is invalid. You are allocating memory for sizeof(int) bytes. You should:
pedido *Pedidos=(pedido *)malloc(sizeof(*Pedidos) * cantidadCartas);
allocate memory for contidadCartas count of pedido structures. The time you access Pedidos memory using pedido* pointer you do undefined behavior.
Your code is really hard to read, badly indented, with strange locale names, no error checking and it leaks memory for all malloc you call. A good code would check all error places if (Pedidos == NULL) { handle_error(); } and if(fscanf("%d", ....) != 1) etc. The allocation of int *typo = malloc(sizeof(int)); straight up leaks memory - it is nowhere freed. I also strongly encourage you to write all code, including all structure, variables and function names in english.

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

Segfaults and referencing struct arrays

I've got a project that involves creating a text game. I'm creating a struct for each player and putting them in an array. I'm then trying to pass in data and then pass by pointer the array to other functions, however I keep on getting segmentation faults (Although on the odd occasion working fine). I've summarised below.
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
char name[9];
int cardsHeld;
int hand[8];
} Player;
void printNames(Player** playerArray)
{
for (int i = 0; i < 3; i++)
{
fprintf(stdout, "%s\n", playerArray[i]->name);
}
}
void gamesetup()
{
int count;
fprintf(stdout, "How many players will be partaking in 'The Game'? ( 1 - 5)\n");
fscanf(stdin, "%d", &count);
Player** playerArray = (Player**)malloc(sizeof(Player*) * count);
for(int i = 0; i < count; i++)
{
playerArray[i] = (Player*) malloc(sizeof(Player));
fprintf(stdout, "Please enter the name for player %d.\n\n", i + 1);
fscanf(stdin, "%s", playerArray[i]->name);
}
printNames(playerArray);
}
int main(int argc, char** argv)
{
gamesetup();
return 0;
}
My questions are;
Is the fscanf getting the address of the Player.name member? I'm getting confused whether the -> operator should deference the value of the struct member or since its in an array the address?
I'm not sure why it works sometimes but not others. If it works sometimes fundamentally it should be ok. Is the malloc function allocating memory it should not or is the fscanf putting data in the wrong place.
Thank you.
-EDIT-
Changed the code so it is in a complete program that appears to work without seg faults. I think that my issues arise from not freeing the memory before termination is messing it up next time I run it without compiling first. I'm still not sure why fscanf works as in my mind the argument playerArray[i]->name is returning the value, not the address.
I've worked it out where I was confused. Thank you for all your help in the comments.
The member I am accessing in my array is a string of chars so the first member is a pointer. By using fscanf(stdin, "%s",playerArray[i]->name); This deferenced the pointer (an address) so it works. I was getting in a muddle as it was an member of an array of structs. The segfaults were caused by me messing with the code to try and fix what already worked.

Function SegFault with Arrays of Structs

I am using this function:
int times_on_table(char *search,struct table index[],int wct){
int ct=0,num=0;
while(ct<wct){
if(strcmp(search,(index[ct].label))==0) {
num++;
}
ct++;
}
return num;
}
to search through an array of structs and find all the times a certain string is stored in the array and returns the number of times the string occurs. Whenever i use this function inside main:
/*EDIT: i had a main from the wrong program my apologies*/
int main(int argc, char **argv){
int numwds=get_num_words(argv[1]);
struct table index[numwds];
int a;
struct cmd_ops symbol[22];
store(argv[1],index,numwds);
ops_gen(symbol);
int b=times_on_table("in",index,numwds);
printf("%d",b);
}
the code works fine. However, when i try to use it inside certain functions like this one
struct table* store(char *filename,struct table index[]) {
FILE *fp;
fp=fopen(filename,"r");
char *a;int d=0,e=0,t=0;
a=malloc(60);
int wordcount=get_num_words(filename);
while(d<wordcount){
fscanf(fp,"%s",a);
if ((index[d].label=strdup(a))==NULL)
break;
index[d].word_num=d;
times_on_table("this",index,wordcount);/*when i comment this out
of my code it runs fine*/
index[d].address=findline(filename,index[d].label,wordcount,index,t);
d++;
}
free(a);
}
the code does not run and gives me a segmentation fault. Any thoughts?
EDIT: I don't know if this helps but when i get the segfault, it happens before even the first line of code in main is executed.
EDIT:here is the other function that causes a segfault when times_on_table() is called:
int findline(char *filename,char *check,int wordcount,struct table index[],int t){
char *a;
a=malloc(60);
int b=line_count(filename);
int ch;
fpos_t pos;
int line=0,wd=0,loc,s=0,c=1,times;
times=times_on_table(check,index,wordcount);
FILE *fp;
fp=fopen(filename,"r");
int list[wordcount];
while(c<=b){
fscanf(fp,"%s",a);
fgetpos(fp,&pos);
ch=fgetc(fp);ch=fgetc(fp);
if(strcmp(a,check)==0){
if(times==0)
return line;
else
times--;
}
if(ch==10){
line++;c++;
}
else
fsetpos(fp,&pos);
}
return line;
}
it was in this function that i first added times_on_table(), and had the segmentation fault keep my program from running.
Here
while(d<wordcount){
fscanf(fp,"%s",a);
if ((index[d].label=strdup(a))==NULL)
break;
index[d].word_num=d;
times_on_table("this",index,wordcount);
you try to count the occurrences of "this" in a wordcount long array, but you have only filled d+1 slots of the array. The other slots may contain garbage, and then accessing index[ct].label is likely to cause a segmentation fault when ct > d.
It is very likely you are going past the array index. These two lines do not really match up (from the code you have shared with us :
int wordcount=get_num_words(filename);
times_on_table("this",index,wordcount);
(wordcount I assume counts something in filename which is passed in as the first parameter, but it seems irrelevant to your struct table index[])
So the parameter being passed in struct table index[], is probably a different size than the value you are storing into wordcount. I would suggest you pass in the array size as a parameter to the store function and use that as you would in your working main example. example
struct table* store(char *filename,struct table index[], int structSize){
....
times_on_table("this",index,structSize); //replace b from the call in main
}
It may be related with setting the "index[d].label" properly. Try to print all the labels outside the times_on_table() function without comparing them with anything.

Resources