Can't deallocate memory in my C program - c

I need your help deallocating memory in below program. I tried as you can see in main, but no success. Can not get how to do it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char name[25];
char street[25];
char citystate[25];
char zip[6];
}student;
typedef student *studinfo;
/*function prototypes*/
void getinfo(student *details[], int *);
int main(void)
{
int count = 0;
student *studptr[49];
getinfo(studptr, &count);/*call getinfo function to get student info*/
/*int i = 0;
for (i; i<count; i++) {
free(studptr[i]->name);
free(studptr[i]->street);
free(studptr[i]->citystate);
free(studptr[i]->zip);
} */
return 0;
}
Below is a function to get the info from the file. I will use this info later on in sort function and in display function to display the results. After that I should deallocate the memory.
void getinfo(student *details[], int *count)
{
char s[100];
studinfo info;
/*Get student information*/
while (gets(s) != NULL) {
info = (studinfo)malloc(sizeof(student));
strcpy(info->name, s);
gets(info->street);
gets(info->citystate);
gets(info->zip);
details[(*count)++] = info; /*Increase the pointer to next position*/
} /* End of while loop*/
} /* End of getinfo */

There are three problems with your code:
You are trying to free components of struct student. Since these component arrays were not allocated with malloc, you cannot free them; you need to free only the struct itself.
You are using gets, which can cause buffer overruns. You should use fgets instead, passing buffer size, and stdin for the FILE* parameter.
You copy s[100] into info->name. This can potentially overrun the buffer, because info->name fits only 25 characters.
Once you fix these issues, your program should run correctly.

It should be:
int i;
for (i = 0; i < count; i++) {
free(studptr[i]);
}
Since you allocated each student as a single block, you free them the same way.

Related

sprintf with struct array field - gets segmentation fault

This idea is to format text info messages bellowing to a structure within a module.
It works like a charm when trying to define the message with (cf module.c):
/*this works*/
module_text3.info_text[0] = "toto[0]";
module_text3.info_text[1] = "toto[1]";
But when using sprintf, I got segmentation fault (cf module.c):
/*this gives segmentation fault*/
for(cpt=0; cpt < 2; cpt++)
{
sprintf(module_text3.info_text[cpt], "info[%u]", cpt);
}
3 different files: main.c, module.h and module.c
/*main.c*/
/*gcc -o test main.c module.c*/
#include <stdio.h>
#include "module.h"
int main(int argc, char **argv)
{
int i;
struct message3 *ptext3 = moduleFcn3();
for (i= 0; i < ptext3->info_nb; i++)
{
printf("ptext3->info_text[%u]: %s\n", i, ptext3->info_text[i]);
}
printf("ptext3->error_text: %s\n", ptext3->error_text);
printf("ptext3->id: %u\n", ptext3->id);
printf("ptext3->info_nb: %u\n", ptext3->info_nb);
printf("ptext3->info_nb_max: %u\n", ptext3->info_nb_max);
return 0;
}
/*------------------------------------------------------*/
/*module.h*/
#define NB_LINE_MAX 10
struct message3
{
char *info_text[NB_LINE_MAX]; /*a few info lines.*/
char *error_text; /*only one line for error.*/
int id;
int info_nb_max;
int info_nb;
};
extern struct message3* moduleFcn3(void);
/*------------------------------------------------------*/
/*module.c*/
#include <stdio.h>
#include "module.h"
/*static is in "Stack".*/
static struct message3 module_text3;
struct message3* moduleFcn3(void)
{
int cpt = 0;
struct message3 *ptext;
/*this gives segmentation fault*/
for(cpt=0; cpt < 2; cpt++)
{
sprintf(module_text3.info_text[cpt], "info[%u]", cpt);
}
/*this works*/
// module_text3.info_text[0] = "toto[0]";
// module_text3.info_text[1] = "toto[1]";
// cpt = 2;
module_text3.error_text = "This is error";
module_text3.id = 4;
module_text3.info_nb_max = NB_LINE_MAX;
module_text3.info_nb = cpt;
ptext = &module_text3;
return ptext;
}
I would appreciate any advises on how to format my information messages (with our without using sprintf).
Thank you,
You have not allocated space for the strings in the info_text field. The simplest thing to do would be to change the struct:
/*module.h*/
#define NB_LINE_MAX 10
#define INFO_MAX 25
struct message3
{
char info_text[NB_LINE_MAX][INFO_MAX]; /*a few info lines.*/
char *error_text; /*only one line for error.*/
int id;
int info_nb_max;
int info_nb;
};
extern struct message3* moduleFcn3(void);
You did not allocate any memory for the info_text strings. You either have to use malloc() first, or if your C library supports it (the GNU one does), use asprintf() instead of sprintf() to have it allocate enough memory to hold the whole output string for you:
for(cpt = 0; cpt < 2; cpt++)
asprintf(&module_text3.info[cpt], "info[%u]", cpt);
Don't forget that you also have to free the memory again at some point.
The reason that the following line works:
module_text3.info_text[0] = "toto[0]";
Is that the compiler ensures the string "toto[0]" is stored in memory somewhere, and you just make the pointer module_text3.info_text[0] point to that string.

how to deal with Segmentation fault in dynamically allocated struct C

I have written a program that reads in words from a text file. There is one word per line. I need to find how many times each word repeats. To find this out so far i have read the words in from the file and placed them all in a dynamically allocated array of struct. My problem is that the program keeps segmentation faulting whenever i try to run it. I assume there is a problem with how i am dynamically allocating the data.
Code is as follows;
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
//struct
struct _data {
char *word;
int number;
};
//scan for size of file
int SCAN(FILE *data) {
int size = 0;
char s_temp[50];
while (1) {
fscanf(data, "%s", s_temp);
if (feof(data)) break;
size++;
}
return size;
}
//load content into struct
int LOAD(FILE *data, int size, struct _data *Wordstruct){
int i;
char temp[50];
for (i=0; i <size; i++){
fscanf(data, "%s", temp , &Wordstruct[i].word, &Wordstruct[i].number);
Wordstruct[i].word =calloc(strlen(temp), sizeof(char));
strcpy(Wordstruct[i].word, temp);
if(strcasecmp(Wordstruct[i].word, temp) ==0){
Wordstruct[i].number++;
}
}
return size;
}
//count how many times each word repeats
void COUNT(struct _data *Wordstruct, int size){
int i;
int count;
count =0;
char *word;
if (strcasecmp(Wordstruct[i].word, word)==0){
count++;
for(i=0; i<size; i++){
printf("%s\n",Wordstruct[i].word,"occurs:\t",count);
}
}
}
//main routine
int main(int argc, char *argv[]){
int size;
FILE *data;
struct _data *Wordlist;
if(argc <2){
printf("Not enough arguments\n");
}
else{
FILE *data= fopen(argv[1],"r");
size =SCAN(data);
LOAD(data, size, Wordlist);
COUNT(Wordlist, size);
}
return 0;
}
You haven't allocated memory for Wordlist. Add
Wordlist = malloc(size*sizeof(*Wordlist));
before the call to LOAD.
And, as pointed out by #BLUEPIXY in comments, change
Wordstruct[i].word =calloc(strlen(temp), sizeof(char));
to
Wordstruct[i].word =calloc(strlen(temp)+1, sizeof(char));
Change this:
Wordstruct[i].word =calloc(strlen(temp), sizeof(char));
To this:
Wordstruct[i].word =calloc(strlen(temp)+1, sizeof(char));
You need to account for NULL terminator, strlen() does not do that for you here.

fscanf only scans in the first value of my file

#include <stdio.h>
#include <stdlib.h>
struct account{
int accountId;
char *name;
double amount;
};
int main(int argc, char **argv)
{
FILE *file=fopen(argv[1],"r");
struct account *Ptr;
int i,j;
int size=0;
fscanf(file,"%d",&size);
if(size==0)
{
printf("Unable to open file");
return 0;
}
printf("%d",size);
Ptr=malloc(sizeof(struct account)*size);
for(i=0;i<size;i++)
{
fscanf(file,"%d%s%lf\n",&(Ptr+i)->accountId,(Ptr+i)->name,&(Ptr+i)->amount);
}
for(j=0;j<size;j++)
{
printf("%d%s%lf\n",((Ptr+j)->accountId),(Ptr+j)->name,((Ptr+j)->amount));
}
fclose(file);
free(Ptr);
return 0;
}
This is used to read in the input file
2
2 Harry 23.45
8 Sally 100.91
Somehow the code reads in the first 2 for size and the second 2 during the for loop but nothing else
Your code has undefined behavior, because you are reading data into an uninitialized pointer:
fscanf(file,"%d%s%lf\n",&(Ptr+i)->accountId,(Ptr+i)->name,&(Ptr+i)->amount);
// ^^^^
// This pointer is uninitialized ----------------------+
There are three ways to address this:
Make name an array, rather than a pointer, e.g. char name[MAX_NAME], or
Use malloc to allocate space to name before reading data into it.
Read into a temporary buffer, then malloc the exact number of chars.

printing data from a struct

I have a nested array of structures in the following form:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
char* e_name;
char* e_lastname;
}emp_name;
typedef struct
{
emp_name name;
int id;
}emp;
int main(int argc, char *argv[])
{
int i;
int cod=100;
emp job[3];
for (i=0;i<3;i++)
{
scanf("%s",&job[i].emp.e_lastname);
job[i].id=cod;
cod++;
}
for (i=0;i<3;i++)
{
printf("%s",job[i].emp.e_lastname);
printf("%d\n",job[i].id);
}
system("PAUSE");
return 0;
}
but the program hangs in the printing part, why is that?
Thanks
You have three problem:
First you want to access:
job[i].name.e_lastname
not
job[i].emp.e_lastname
Second You should have:
scanf("%s",&job[i].name.e_lastname);
instead of
scanf("%s",job[i].name.e_lastname);
You do not pass & since it is an array you are passing to the scanf function.
Third problem you should allocate memory to your char *e_lastname and char *e_name camps of the struct emp_name.
Note that:
scanf
int scanf ( const char * format, ... );
Reads data from stdin and stores them according to the parameter
format into the locations pointed by the additional arguments.
The additional arguments should point to already allocated objects
of the type specified by their corresponding format specifier within
the format string. (source)
So you want this:
int main(int argc, char *argv[])
{
int i;
int string_size = 10;
int cod=100;
emp job[3];
for (i=0;i<3;i++) // Allocate space for the string you will access.
{
job[i].name.e_name = malloc(sizeof(char)*string_size);
job[i].name.e_lastname = malloc(sizeof(char)*string_size);
}
for (i=0;i<3;i++)
{
scanf("%s",job[i].name.e_lastname);
job[i].id=cod;
cod++;
}
for (i=0;i<3;i++)
{
printf("%s",job[i].name.e_lastname);
printf("%d\n",job[i].id);
}
system("PAUSE");
return 0;
}
Consider the fact that using scanf is unsafe, because:
If you use the %s and %[ conversions improperly, then the number of
characters read is limited only by where the next whitespace character
appears. This almost cetainly means that invalid input could make your
program crash, because input too long would overflow whatever buffer
you have provided for it. No matter how long your buffer is, a user
could always supply input that is longer. A well-written program
reports invalid input with a comprehensible error message, not with a
crash. (source)
Nevertheless, their are some workaround that you can do to use scanf (check them here)
Instead of scanf you can use fgets. fgets allows you to limit the data that will be placed in your buffer.
You really need to be careful with pointers and what is allocated or not.
I have rewritten your code but with the wrong solution. check comments.
#include <stdio.h>
#include <stdlib.h>
typedef struct emp_name {
/*
* now there you had just char*. this decares
* a pointer to some memory but no memory is allocated.
* if you were going with that approach you should initialize
* the struct and assign those values to something you malloc'ed().
* This version suffers from fixed size and a possible buffer overflow if
* you chose scanf to write the data in the buffer.
*/
char e_name[512];
char e_lastname[512];
/*
* try to follow conventions. your previous struct declarations
* were anonymous. if it caught an error you wouldn't know in which
* struct it would be. good practices here: link1 (bottom)
*/
} emp_name_t;
typedef struct emp {
emp_name_t emp;
int id;
} emp_t;
int main(int argc, char *argv[]) {
int i;
int cod=100;
emp job[3];
for (i=0;i<3;i++) {
/*
* check out this excelent post for a secure alternative:
* link2 (bottom)
*/
scanf("%s",&job[i].emp.e_lastname);
job[i].id=cod;
cod++;
}
for (i=0;i<3;i++) {
printf("%s",job[i].emp.e_lastname);
printf("%d\n",job[i].id);
}
return 0;
}
link1: openbsd style(9)
link2: disadvantages of scanf
I see you have:
typedef struct
{
char* e_name;
char* e_lastname;
}emp_name;
typedef struct
{
emp_name name;
int id;
}emp;
emp job[3];
So what is .emp doing in the following line? Its not a member of any structure
job[i].emp.e_lastname

Segmentation error in Xcode, debugger cant help me

I have been going crazy trying to figure out what is done wrong. I admit I am inexperienced when it comes to C, but I don't know what is wrong. Is the way that I am accessing/using the struct incorrect?
EDIT: I keep getting EXC_BAD_ACCESS in debugger.
#include <stdio.h>
#include <string.h>
#define MAX_STRING 20
#define MAX_PLYR 16
typedef struct {
char pname[MAX_STRING];
int runs;
char *s;
} Team_t;
int
main(void)
{
Team_t *team_data[MAX_PLYR];
int i;
char *p;
char name[MAX_STRING];
FILE *inp;
inp = fopen("teamnames.rtf", "r");
for (i = 0; i < MAX_PLYR;) {
while ((fgets(name, MAX_STRING, inp) != NULL));
printf("Name(i): %s\n", name);
strcpy(team_data[i]->pname, name);
i++;
}
fclose(inp);
return(0);
}
Edit: Here's what's changed, still getting Segmentation Error
#include <stdio.h>
#include <string.h>
#define MAX_STRING 20
#define MAX_PLYR 16
typedef struct {
char pname[MAX_STRING];
int runs;
char s;
} Team_t;
int
main(void)
{
Team_t team_data[MAX_PLYR];
char name[MAX_STRING];
int i;
FILE *inp;
inp = fopen("teamnames.rtf", "r");
for (i = 0; i < MAX_PLYR; i++) {
((fgets(name, MAX_STRING, inp)));
if (feof(inp)) {
printf("End of stream\n");
i = MAX_PLYR;
}
else {
if (ferror(inp)) {
printf("Error reading from file\n");
}
printf("Name(i): %s\n", name);
strcpy(team_data[i].pname, name);
}
}
fclose(inp);
return(0);
}
You declare team_data but you don't allocate it; therefore it's pointing off into random memory, as are the imaginary contents of the array. You need to actually create the array, something like
Team_t *team_data[MAX_PLYR] = (Team_t**) malloc(MAX_PLYR * sizeof(Team_t *));
Use structs, not pointers (or if you insist using pointers the allocate space for those structs)
Team_t team_data[MAX_PLYR];
fgets(team_data[i].pname, MAX_STRING, inp)
when you write
Team_t *team_data[MAX_PLYR];
you are not allocating any memory for the actual Team_t records, instead you are setting up an array of pointers to records.
If instead you would write
Team_t team_data[MAX_PLYR];
you would have allocated the records. When you then want to copy into the team_data array you write instead
strcpy( team_data[i].name, name );

Resources