printing data from a struct - c

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

Related

Struct in a struct using typedef - C

How do I properly use one struct inside another struct using typedef in C?
This method doesn't work and I can't understand why:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
char *nume;
char *prenume;
data data;
} student;
typedef struct
{
int an,zi,luna;
} data;
int main()
{
student Andrei;
scanf("%s %s %d ",Andrei.nume,Andrei.prenume,&Andrei.b.an);
printf("%s %s %d ",Andrei.nume,Andrei.prenume,Andrei.data.an);
return 0;
}
There are actually a number of errors in your code!
First, you need to declare/define any struct object before you use that as a member of another struct.
Second, your nume and prenume members are declared as pointers to characters but they are not initialized to anything, nor is any memory allocated for those string.
Third, you have a 'typo' in your scanf line: Andrei.b.an should, presumably, be Andrei.data.an.
Finally (I think), because you have a trailing space in the format string for scanf, the function will need at least one 'extra' input field in order to complete.
Here is a potential 'fix', with comments added where I've made changes:
#include <stdio.h>
// <stdlib.h> // You don't use this - perhaps thinking of using "malloc" for "nume" and "prenume"??
typedef struct // This MUST be defined BEFORE it is used as a member in the following struct!
{
int an, zi, luna;
}data;
typedef struct
{
char nume[32]; // Here, we create fixed char arrays (strings) for "nume"...
char prenume[32]; // ... and "prenume". You can change the sizes, as you need!
data data;
} student;
int main()
{
student Andrei;
scanf("%s %s %d", Andrei.nume, Andrei.prenume, &Andrei.data.an); // Note: removed trailing space from format!
printf("%s %s %d", Andrei.nume, Andrei.prenume, Andrei.data.an);
return 0;
}

Malloc and Struct

i am facing some difficulties with malloc and structs. I want to read the m_data.number_chars as shown in my code (which is an integer) to be the memory that i want to allocate.. But when i compile my code, and run it, it crushes.. Any ideas..? Thanks in advance!
#include <stdio.h>
struct movies {
int number_chars;
char name;
int made_year;
float money;
};
struct movies m_data;
int main()
{
scanf("%d",&m_data.number_chars);
m_data.name=malloc(m_data.number_chars);
gets(m_data.name);
printf("%s",m_data.name);
}
Well you were supposed to pass char* to the scanf - more specifically address of the variable on which input will be stored. You didn't do that.
No return value check for the standard functions and ofcourse you didn't use malloc earlier.
#include <stdio.h>
#include <stdlib.h>
struct movies {
int number_chars;
char* name;
int made_year;
float money;
};
struct movies m_data;
int main(void)
{
if( scanf("%d",&m_data.number_chars)!= 1){
fprintf(stderr, "%s\n", "Error in input");
exit(EXIT_FAILURE);
}
getchar();
if(m_data.number_chars <= 0){
fprintf(stderr, "%s\n", "Error in number of character count");
exit(EXIT_FAILURE);
}
m_data.name = malloc(m_data.number_chars+1);
if(!m_data.name){
perror("Malloc error");
exit(EXIT_FAILURE);
}
if(fgets(m_data.name,m_data.number_chars+1,stdin)){
printf("[%s]\n",m_data.name);
}
return 0;
}
When calling scanf, you need to pass the address of the variable to hold the result (using the ampersand &). This would definitely cause serious memory problems right there.
Also, name is of type char. char is not a pointer. Therefore, you cannot assign the result of malloc() to name.
You need a pointer type.
Also, "crushes" is not a technical description of what is going wrong. You'll probably get further if you can articulate your situation better.
Try:
#include <stdio.h>
#include <stdlib.h>
struct movies {
int number_chars;
char *name;
int made_year;
float money;
};
struct movies m_data;
int main()
{
scanf("%d",&m_data.number_chars);
m_data.name=malloc(m_data.number_chars);
gets(m_data.name);
printf("%s",m_data.name);
free(m_data.name)
}

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.

Why I am having a Segmentation fault?

/* This Program generates a file with a pseudo-random number of st_record_t structures. The file is passed by command line arguments. The program must by executed, in UNIX, this way: ./file_gen -path <path> */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "types.h"
#define MSG_INVALID_INPUT "Your input was not valid"
#define CMD_FLAG_PATH_POSITION 1
#define CMD_ARG_PATH_POSITION 2
#define CMD_FLAG_PATH "-path"
#define SDM_MAX 10000.0
status_t validate_arguments (int argc, char * argv []);
int main (int argc, char * argv [])
{
FILE * fi;
size_t i;
st_record_t aux_struct, aux2_struct;
int size;
if ((validate_arguments(argc, argv))!= OK)
{
fprintf(stderr, "%s\n", MSG_INVALID_INPUT);
return EXIT_FAILURE;
}
if((fi = fopen(argv[CMD_ARG_PATH_POSITION], "wb")) == NULL)
return EXIT_FAILURE;
srand(time(NULL));
for (i=0; i<(size=100); i++)
{
aux_struct.SDM = (((float)rand()/(float)(RAND_MAX)) * SDM_MAX); /*pseudo-random real number between 0 and SDM_MAX*/
(aux_struct.ID) = i;
(aux_struct.coordinates)->latitude.deg = rand()%180;
(aux_struct.coordinates)->latitude.min = rand()%60;
(aux_struct.coordinates)->latitude.sec = rand()%60;
(aux_struct.coordinates)->longitude.deg = rand()%180;
(aux_struct.coordinates)->longitude.min = rand()%60;
(aux_struct.coordinates)->longitude.sec = rand()%60;
if((fwrite (&aux_struct, sizeof(st_record_t), 1, fi))!=1)
return ERROR_WRITING_FILE;
}
if(fclose(fi) == EOF)
return EXIT_FAILURE
return EXIT_SUCCESS;
}
The problem is with the (aux_struct.coordinates)->latitude.deg = rand()%180 lines. If instead of using a random number I select one, this won't happen
The st_record_t struct is defined this way:
typedef struct {
unsigned char deg, min, sec;
}angle_t;
typedef struct {
angle_t latitude, longitude;
}st_coord_t;
typedef struct {
float SDM;
size_t ID;
st_coord_t * coordinates;
}st_record_t;
The segmentation fault has nothing to do with random number, it's because you never allocate memory for aux_struct.coordinates.
To fix the problem, use something like:
aux_struct.coordinates = malloc(sizeof(st_coord_t));
Remember to free the memory when it's not used any more.
In addition to the issue of the missing initialization of the "coordinates" member, it should be pointed out that the fwrite() will not do what you want. It will just write the contents of the st_record_t. The value of the pointer "coordinates" has no meaning outside the process that is doing the writing and the data in the st_coord_t structure it points to will not get written at all.
You might want to look at something like hdf5 to write complex binary data structures to file in a portable way.
You have
typedef struct {
float SDM;
size_t ID;
st_coord_t * coordinates;
}st_record_t;
As you can see,coordinates is a pointer of type st_coord_t. You need to allocate memory for it using malloc:
aux_struct.coordinates=malloc(sizeof(st_coord_t));
And you need to free the allocated memory after its use using:
free(aux_struct.coordinates);
Note that you must allocate memory for coordinates in aux2_struct if you want to use it and later free it after its use.

Can't deallocate memory in my C program

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.

Resources