Struct initialized in function loses values (although it's an array) - c

I'm trying to initialize array *dip inside "leggif1", inside it if you do a print it's all normal but if you try to print in the main, after the initialization, everything loses its values.
Same thing happen with ADT of first grade "Divisione" and i can't understand why (even though they are passed "by reference" thanks to their pointers).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int matricola;
char nome[20+1],cognome[20+1];
int comp[4];
}dipendente;
typedef struct divisione *Divisione;
struct divisione{
dipendente *dip;
char nome[10+1];
int terna[4][3]; //numero minimo di addetti,competenza minima totale, competenza ottimale totale
//per ognuna delle 4 tipologie
};
void leggif1(dipendente *dip, char *filename);
int leggif2(Divisione *Div, char *filename);
void DIVstampa(Divisione *Div,char *filename,int D);
Divisione DIVinit();
void DIVfree(Divisione *Div);
int main(int argc,char **argv) {
dipendente *dip;
Divisione *Div;
leggif1(dip,argv[1]);
int D=leggif2(Div, argv[2]);
DIVstampa(Div,"stdout",D);
return 0;
}
void leggif1(dipendente *dip, char *filename) {
FILE *fp=fopen(filename,"r");
int i,N;
fscanf(fp,"%d",&N);
dip=malloc(N*sizeof(dipendente));
for(i=0;i<N;i++)
fscanf(fp,"%d %s %s %d %d %d %d",&dip[i].matricola,dip[i].nome,dip[i].cognome,
&dip[i].comp[0],&dip[i].comp[1],&dip[i].comp[2],&dip[i].comp[3]);
}
int leggif2(Divisione *Div, char *filename) {
FILE *fp=fopen(filename,"r");
int i,j,D;
fscanf(fp,"%d",&D);
Div=malloc(D*sizeof(Divisione));
for(i=0;i<D;i++)
Div[i]=DIVinit();
for(i=0;i<D;i++) {
fscanf(fp, "%s", Div[i]->nome);
for (j = 0; j < 4; j++)
fscanf(fp, "%d %d %d", &Div[i]->terna[j][0], &Div[i]->terna[j][1], &Div[i]->terna[j][2]);
}
return D;
}
void DIVstampa(Divisione *Div, char *filename, int D) {
FILE *fp;
if(strcmp(filename,"stdout")==0)
fp=stdout;
else
fp=fopen(filename,"w");
int i,j;
for(i=0;i<D;i++) {
fprintf(fp,"%s\n", Div[i]->nome);
for(j=0;j<4;j++)
fprintf(fp,"%d %d %d\n", Div[i]->terna[j][0], Div[i]->terna[j][1], Div[i]->terna[j][2]);
}
}
Divisione DIVinit(){
Divisione Div=malloc(sizeof (*Div));
return Div;
}
void DIVfree(Divisione *Div){
free(Div);
}

The leggif1 function ignores the value of dip and assigns it a new value. That value is never returned to main.
The type of dip is dipendente* and when called in main the value of the pointer is passed to the function. Overwriting that local copy in the function does not affect the value of the pointer in main.
C only has 'call by value', always make sure you known what that value represents.
This can be solved by returning the dip from the function instead of taking it as a parameter:
dipendente* leggif1(char *filename)
{
//open file and read N
dipendente *dip = malloc(N * sizeof *dip);
if (!dip) {
return NULL;
}
// read in the data
return dip;
}
another way is to use a dipendente** (a pointer to a pointer) but that would, in this case, make the code needlessly complex.
The leggif2 function has the same problem.

Related

Why does this code only writes the first and the last occurrences of nome, cognome and cf?

Why does this code only writes the first and the last occurrences of nome, cognome and cf?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct data{
char nome[20];
char cognome[20];
char cf[20];
}data;
void leggi_file(FILE *input, data **array, int *dim);
void aggiorna(data *vect, char *nome, char *cognome, char *cf, int dim);
void scrivi_file(FILE *output, data *vect, int dim);
int main(void){
FILE *input, *output;
input = fopen("prog1file.txt", "r");
output = fopen("prog1file2.txt", "w");
data *vect1;
int dim_vect1 = 0;
leggi_file(input,&vect1,&dim_vect1);
char *nome="Michele", *cognome="Nappi", *cf="nppmhl69p22b119f";
aggiorna(vect1, nome, cognome, cf, dim_vect1);
scrivi_file(output, vect1, dim_vect1);
return 0;
}
void leggi_file(FILE *input, data **array, int *dim){
char nome[20], cognome[20], cf[17];
int i;
while(fscanf(input, "%s %s %s", nome, cognome, cf) == 3)
(*dim)++;
*array = malloc((*dim + 1) * sizeof(data));
rewind(input);
for(i=0; i<(*dim); i++)
fscanf(input, "%s %s %s", array[i]->nome, array[i]->cognome, array[i]->cf);
}
void aggiorna(data *vect, char *nome, char *cognome, char *cf, int dim){
strcpy(vect[dim].nome, nome);
strcpy(vect[dim].cognome, cognome);
strcpy(vect[dim].cf, cf);
}
void scrivi_file(FILE *output, data *vect, int dim){
int i;
for(i=0; i<(dim+1); i++)
fprintf(output, "%s %s %s\n", vect[i].nome, vect[i].cognome, vect[i].cf);
}
It should write the occurrences of nome, cognome and cf that are stored in the first file in the second, and then add another one which was passed from the main. Why does it only write the first and the last?
In the output file I get something like this:
Giuseppe Nappo nppgspmhl65t23c126a
Michele Nappi nppmhl69p22b119f
In the leggi_file function, array is a pointer to a pointer of structures. Think of it as a pointer to an array of structures. It is most definitely not an array of pointers to structures (as the use array[i]->nome would indicate).
The correct way is to dereference the pointer to get the array (of structures), as in (*array)[i].nome.
With array[i]->nome you treat array as an array of pointers, which it is not. It's (effectively, but not semantically) a pointer to an array.
By using array[i]->nome you will go out of bounds of the memory for array, leading to undefined behavior. You're lucky (or unlucky depending on point of view) that the code don't crash.
The only line you need to change is this one:
fscanf(input, "%s %s %s", array[i]->nome, array[i]->cognome, array[i]->cf);
Which you should change into
fscanf(input, "%s %s %s", (*array)[i].nome, (*array)[i].cognome, (*array)[i].cf);

Incompatible pointer type when making structure of function pointers

I'm trying to make a array of structures which contain a string and a function pointer, however when I compile I get a warning that I've initialized from an incompatible pointer type.
I have no idea why (sorry if I sound ignorant, I'm fairly new to C programming).
typedef struct
{
char Player1[2], Player[2], **gameGrid;
int height,width;
int moveNum, player1Num, player2Num;
bool player1Win, player2Win;
}Game;
typedef int (*pointer_func)(Game *);
typedef struct
{
char *funcName;
pointer_func *f;
}userFunc;
int save(Game *struc);
int load(Game *struc);
int move(Game *struc);
int quit(Game *struc);
void free_grid(Game *struc);
int main(){
//initialised variables
userFunc Name_arr[] = {
{"save",save},
{"load",load},
{"quit",quit},
{"move",move}
};
The four functions being referenced are as follows:
int save(Game *struc)
{
char *str, *inputString, *writeString;
FILE *fp;
int nextPlayer;
int maxRead = 20;
bool DIRresponse;
while(true)
{
printf("Please provide a file name (20 characters max): ");
inputString = input_String(inputString, maxRead, stdin);
if((DIRresponse = check_Directory(inputString)) == true){
printf("That name already exists, choose another\n");
continue;
}
else
break;
}
if(struc->moveNum % 2 == 0)
nextPlayer = struc->player1Num;
else
nextPlayer = struc->player2Num;
sprintf(str,"%s.txt",inputString);
fp = fopen(str,"w");
sprintf(writeString, "%d %d %d %d %d", nextPlayer, struc->height,
struc->width, struc->moveNum, struc->moveNum);
fprintf(fp,writeString);
fclose(fp);
return 0;
}
int move(Game *struc)
{
return 1;
}
int load(Game *struc)
{
return 1;
}
int quit(Game *struc)
{
free_grid(struc);
exit(EXIT_SUCCESS);
}
You have a mismatch in levels of pointers:
typedef int (*pointer_func)(Game *); << Pointer type
typedef struct
{
char *funcName;
pointer_func *f; << Pointer to a pointer type.... OOPS
}userFunc;
Make *f -> f and it should work.

Allocating memory for an array of struct i get an error

the code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 20
typedef struct word{
char word[20];
int occurrance;
} word;
int array_word_creator(word *array, FILE *fp);
void initialize(word array[], int max);
void comparator(word array[], int max, FILE *fp);
void printer(word array[], int max);
int main(int argc, char *argv[])
{
FILE *f_sent, *f_words;
word *array;
int arr_lenght=0;
if(argc!=3)
{
printf("Wrong argument number, please use NAME FILE1 FILE2;\n");
exit(EXIT_FAILURE);
}
if((f_sent=fopen(argv[1], "r"))==NULL||(f_words=fopen(argv[1], "r"))==NULL)
{
printf("Can't find or open the files, please check if the name is correct\n");
exit(EXIT_FAILURE);
}
arr_lenght=array_word_creator(array, f_words);
comparator(array, arr_lenght ,f_sent);
printer(array, arr_lenght);
return 0;
}
int array_word_creator(word *array, FILE *fp)
{
int n,i=0;
fscanf(fp,"%d",&n);
*array= malloc(n*sizeof(word));
while(fscanf(fp,"%s", array[i].word)!=EOF)
{
i++;
}
initialize(array,n);
return n;
}
void initialize(word array[], int max)
{
int i;
for(i=0;i<max;i++)
{
array[i].occurrance=0;
}
}
void comparator(word array[], int max, FILE *fp)
{
char word[MAX];
int i;
while(fscanf(fp,"%s", word)!=EOF)
{
for(i=0;i<max;i++)
{
if(strcmp(word, array[i].word)==0)
{
array[i].occurrance++;
}
}
}
}
void printer(word array[], int max)
{
int i;
for(i=0;i<max;i++)
{
if(array[i].occurrance>0)
{
printf("The word '%s' occurs %d times\n", array[i].word, array[i].occurrance);
}
}
}
And the compiler says me:
C:\Users\Matteo\Google Drive\Programming\C\lab3\es1\main.c|47|error: incompatible types when assigning to type 'word' from type 'void *'|
I just studied memory allocation so i'm having some trouble with it, especially with structures. If possible, plase link me also some good docs about this subject.
thank you!
In main word *array is a pointer to a structure of type word.
You then pass array, which does not point to anything, to the function array_word_creator.
You then try to assign the pointer returned by malloc to where array is pointing, but it doesn't point anywhere yet, and even if it did, it would be pointing to a word (since it is a word *), so it can't store a pointer, hence the compiler error.
If you want to set the array pointer in main to the result of malloc, you have to pass a pointer to the pointer. int array_word_creator(word **array, FILE *fp), then you would call it by doing array_word_creator(&array, .... ), the your *array = malloc will work.
You want this:
...
arr_lenght = array_word_creator(&array, f_words);
...
int array_word_creator(word **array, FILE *fp)
{
int n, i = 0;
fscanf(fp, "%d", &n);
*array = malloc(n * sizeof(word));
while (fscanf(fp, "%19s", (*array)[i].word) != EOF)
{
i++;
}
initialize(*array, n);
return n;
}

command line arguments issues

At the moment the program is reading "unable to open the input file" which means the size is 0. I made the input file with my editor, but I'm not sure what the issue could be. Is there anything up with my code that could cause this? Or is it more likely I just messed up the input.txt file?
#include <stdio.h>
#include <stdlib.h>
int load_data(char* filename, int *x, float *y)
{
int i=0;
FILE* file=fopen(filename,"r");
if(file==NULL)
{
return 0;
}
int size;
fscanf(file, "%d", &size);
for(i=0;i<size;i++)
{
fscanf(file, "%d%f", &x, &y);
}
fclose(file);
return size;
}
void print_data(int *acn, float *amt, int size)
{
int i;
int *p;
for(i=0;i<size;i++)
{
printf("%-10d%-10f ", *(acn+i), *(amt+i));
}
}
int main(int argc, char** argv)
{
int size=0, *x;
char *filename;
float *y;
if(argc!=3)
{
printf("\nInsufficient arguments.\n");
return 0;
}
int n=atoi(argv[2]);
int *acn;
float *amt;
int *fp=malloc(sizeof(int)*n);
if(size==0)
{
printf("\nUnable to open the input file.\n");
return 0;
}
load_data(filename, x, y);
print_data(acn, amt, size);
free(fp);
return 0;
}
There are number of problems in you program -
You are name of file from commal line but you do not store it in char *filename; and in function int load_data(char* filename, int *x, float *y)
you are passing filename.But filename does not have the name of file in it stored.
fscanf(file, "%d%f", &x, &y); when you pass pointer in fscanf with %d you don't need & operator.Just this will do-
fscanf(file, "%d%f", x, y);
You need to allocate memory using malloc to x and y.
size in both functions are different as you declare it again in the function and in main.Thats why size is always 0 in int main.
void print_data in this function you are printing value of acn and amt but both the pointer are unintialized and you are printing it so it will give undefined behaviour.
Also you have pointers which are declared in your program but not used .
In following lines of code (which you have posted), the value of size variable is 0. The value has never been updated, before checking at line if(size==0). That is why this if check is returning true and printing "Unable to open the input file".
You may want to set the value of size variable before this if check.
int size=0, *x; //HERE YOU ARE WRITING "SIZE" VARIABLE
char *filename;
float *y;
if(argc!=3)
{
printf("\nInsufficient arguments.\n");
return 0;
}
int n=atoi(argv[2]);
int *acn;
float *amt;
int *fp=malloc(sizeof(int)*n);
if(size==0) //HERE YOU ARE READING/CHECKING "SIZE" VARIABLE. THERE IS NO CHECGE IN VARIABLE BEFORE THIS SO, VALUE IS STILL '0'
{
printf("\nUnable to open the input file.\n");
return 0;
}

Realloc an int array

I'm trying to create an array to hold an int, then when another int is to be added increase it in size to hold another int.. and so on..
I know it's not an efficient use of realloc, but it's proof on concept more than anything else. Just to get it working would allow me to optimise it and be able to apply it to something useful. A working example. The problem comes when i call the print function and it just segfaults. Any help would be appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef char String[100];
void begin(int *);
void add(int *, int);
void print(int *);
int tempcount=0;
int main(void)
{
int *n=NULL;
String menu;
begin(n);
while(true)
{
scanf("%9s", menu);
if(!strcmp("a", menu)) //add
{
int i=0;
scanf("%d", &i);
add(n, i);
}
else if(!strcmp("p", menu)) //print
{
print(n);
}
else if(!strcmp("q", menu)) //quit
{
free(n);
break;
}
}
return 0;
}
void begin(int *n)
{
n=malloc(sizeof(int));
if(n==NULL)
{
printf("Error in malloc!");
return;
}
n[0]=0;
printf("Added %d \n", n[0]);
}
void add(int *n, int numToAdd)
{
static int sizeCount=0;
sizeCount++;
tempcount=sizeCount;
int *temp;
temp=realloc(n, (sizeCount+1) * sizeof(int));
if(temp==NULL)
{
printf("Error in realloc!");
return;
}
n=temp;
n[sizeCount]=numToAdd;
printf("Added %d \n", n[sizeCount]);
}
void print(int *n)
{
int i;
for(i=0; i<tempcount; i++)
{
printf("%d ", n[i]);
}
}
You need to pass a pointer to your pointers in add/begin so they can modify your pointer in main
begin(&n);
...
add(&n, i);
and your definition
void begin(int **n)
{
*n=malloc(sizeof(int));
if(*n==NULL)
{
printf("Error in malloc!");
return;
}
(*n)[0]=0;
printf("Added %d \n", (*n)[0]);
}
and
void add(int **n, int numToAdd)
{
static int sizeCount=0;
sizeCount++;
tempcount=sizeCount;
int *temp;
temp=realloc(*n, (sizeCount+1) * sizeof(int));
if(temp==NULL)
{
printf("Error in realloc!");
return;
}
*n=temp;
(*n)[sizeCount]=numToAdd;
printf("Added %d \n", (*n)[sizeCount]);
}
Right now what you're doing is modifying local copies of your pointer in begin/add, so when you change it in those functions it's not modifying your pointer n in main
Also, fun fact, if you pass NULL as the first parameter to realloc it acts like a malloc, so if you initialize n to NULL, you can simply call add without first doing a begin.
Check your function add - are you sure you update the pointer value?
Try with ** as a parameter - I think it will help.

Resources