i want to use nested structures with pointers in c. i write this code but i dont know why this code not working. actually how can i allocate memory for my second structure?
#include <stdio.h>
#include <stdlib.h>
struct address
{
int code;
char city[10];
};
struct student {
char name[10];
struct address *ads;
} *person1;
int main()
{
person1 = malloc(sizeof(struct student));
scanf("%s", person1->name);
scanf("%d", &person1->ads->code);
scanf("%s", person1->ads->city);
printf("%s", person1->name);
printf("%d", person1->ads->code);
printf("%s", person1->ads->city);
return 0;
}
NOTE: when i use "person1->ads = malloc(sizeof(struct address));" program ran to problem and stop working.
[Update from comment:]
I use DEV C++ v5.4.2
You need to also allocate memory for members stored via pointer.
int main()
{
person1 = malloc(sizeof(struct student));
person1->ads = malloc(sizeof(struct address));
scanf("%s", person1->name);
scanf("%d", &person1->ads->code);
scanf("%s", person1->ads->city);
printf("%s", person1->name);
printf("%d", person1->ads->code);
printf("%s", person1->ads->city);
free(person1->ads);
free(person1);
return 0;
}
You have a few poblems
You don't check the success of malloc.
You don't malloc for person1->ads member.
You don't check the success of scanf.
This is a fixed and anotated version of your code
#include <stdio.h>
#include <stdlib.h>
struct address
{
int code;
char city[10];
};
struct student
{
char name[10];
struct address *ads;
};
int main()
{
/* You don't need te struct to be global, and it's generally a bad idea, not always of course */
struct student *person;
/* you should check that malloc succeeded otherwise undefined behavior would happen */
person = malloc(sizeof(*person));
if (person == NULL)
{
printf("cannot allocate memory\n");
return -1;
}
/* you should check that scanf succeeded too */
if (scanf("%9s", person->name) != 1)
/* ^ prevent buffer overflow */
{
printf("Invalid, input\n");
free(person);
return -1;
}
person->ads = malloc(sizeof(*(person->ads)));
if (person->ads == NULL)
{
printf("cannot allocate memory\n");
/* on failure free successfuly allocated person */
free(person);
return -1;
}
/* you should check that scanf succeeded too */
if (scanf("%d", &person->ads->code) != 1)
{
printf("Invalid, input\n");
free(person->ads);
free(person);
return -1;
}
/* you should check that scanf succeeded too */
if (scanf("%9s", person->ads->city) != 1)
/* ^ prevent buffer overflow */
{
printf("Invalid, input\n");
free(person->ads);
free(person);
return -1;
}
printf("Name: %s\n", person->name);
printf("Code: %d\n", person->ads->code);
printf("City: %s\n", person->ads->city);
free(person->ads);
free(person);
return 0;
}
how can i allocate memory for my second structure?
For example the same way as you did for the first structure: allocate it from the heap
#include <stdlib.h>
#include <stdio.h>
struct address
{
int code;
char city[10];
};
struct student
{
char name[10];
struct address * ads;
};
int main(void)
{
struct student * person1 = malloc(sizeof * person1);
if (NULL == person1)
{
perror("malloc() failed for person1");
}
else
{
person1->ads = malloc(sizeof * person1->ads);
if (NULL == person1->ads)
{
perror("malloc() failed for person1->ads");
}
else
{
/* scan and print */
free(person1->ads);
}
free(person1);
}
}
Related
I have project in school where in need to make a struct of AirportManager which holds the amount of airports and an array of Airport (another struct). I started writing the code but I having trouble with the malloc of the array of airports.
I attahced to code I write so far, the problem I have is that the values dont saved in the airportArray in the AirportManager.
//AirportManger Struct
typedef struct {
Airport* airportArray;
int airportAmount;
}AirportManager;
void initAirportManager(AirportManager* airportManager)
{
airportManager->airportAmount = 0;
airportManager->airportArray = (AirportManager*)malloc(0);
}
void addAirport(AirportManager* airportManager)
{
Airport airport;
printf("Enter Airport Name: ");
scanf("%s", airport.airportName);
printf("Enter Airport Address: ");
scanf("%s", airport.airportAddress);
airportManager->airportAmount++;
airportManager->airportArray = (Airport*)realloc(airportManager->airportArray, airportManager->airportAmount * sizeof(Airport));
airportManager->airportArray = airport;
}
//Airport Struct
typedef struct {
char airportName[MAX];
char airportAddress[MAX];
}Airport;
//Main
AirportManager airportManager;
initAirportManager(airportManager);
addAirport(&airportManager);
The code has some issues. We shouln't:
allocate zero bytes with malloc(0)
assign twice to airportManager->airportArray
use scanf
Here is the code modified. It uses malloc and realloc better, and fgets instead of scanf.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZ 512
typedef struct {
char airportName[SIZ];
char airportAddress[SIZ];
} Airport;
typedef struct {
Airport* airportArray;
int airportAmount;
} AirportManager;
// Call first on AirportManager
void initAirportManager(AirportManager* airportManager)
{
airportManager->airportAmount = 0;
airportManager->airportArray = NULL;
}
// Call last on AirportManager
void finalAirportManager(AirportManager* airportManager)
{
airportManager->airportAmount = 0;
if (airportManager->airportArray != NULL)
free(airportManager->airportArray);
airportManager->airportArray == NULL;
}
// Add an airport to the manager
void addAirportByNameAndAddress(AirportManager* airportManager, char *name, char *address)
{
// Calculate the amount of memory needed
size_t mem = (airportManager->airportAmount + 1) * sizeof(Airport);
// Get the memory required
Airport* newAirports = NULL;
if (airportManager->airportArray == NULL)
newAirports = (Airport*)malloc(mem);
else
newAirports = (Airport*)realloc(airportManager->airportArray, mem);
if (newAirports == NULL)
{
// error: out of memory
return;
}
// Copy the name and the address to new the new Airport
Airport *current = newAirports + airportManager->airportAmount;
memset(current->airportName, '\0', SIZ);
strncpy(current->airportName, name, SIZ - 1);
memset(current->airportAddress, '\0', SIZ);
strncpy(current->airportAddress, address, SIZ - 1);
// Update the manager
airportManager->airportAmount++;
airportManager->airportArray = newAirports;
}
void addAirport(AirportManager* airportManager)
{
char name[SIZ] = { 0 };
char address[SIZ] = { 0 };
printf("Enter Airport Name: ");
fgets(name, SIZ - 1, stdin);
printf("Enter Airport Address: ");
fgets(address, SIZ - 1, stdin);
addAirportByNameAndAddress(airportManager, name, address);
}
void main() {
AirportManager airportManager;
initAirportManager(&airportManager);
addAirport(&airportManager);
finalAirportManager(&airportManager);
}
I have an array of structs I would like to write to a binary file. I have a write.c program and a read.c program. The write.c program seems to be working properly but when I run the read.c program I get a segmentation fault. I'm new to C so It would be great if someone could look over my code for any obvious errors. I promise it's not too long :)
write.c:
#include <stdlib.h>
#include <stdio.h>
struct Person
{
char f_name[256];
char l_name[256];
int age;
};
int main(int argc, char* argv[])
{
struct Person* people;
int people_count;
printf("How many people would you like to create: ");
scanf("%i", &people_count);
people = malloc(sizeof(struct Person) * people_count);
int n;
for (n = 0; n < people_count; n++)
{
printf("Person %i's First Name: ", n);
scanf("%s", people[n].f_name);
printf("Person %i's Last Name: ", n);
scanf("%s", people[n].l_name);
printf("Person %i's Age: ", n);
scanf("%i", &people[n].age);
}
FILE* data;
if ( (data = fopen("data.bin", "wb")) == NULL )
{
printf("Error opening file\n");
return 1;
}
fwrite(people, sizeof(struct Person) * people_count, 1, data);
fclose(data);
return 0;
}
read.c:
#include <stdlib.h>
#include <stdio.h>
struct Person
{
char f_name[256];
char l_name[256];
int age;
};
int main(int argc, char* argv[])
{
FILE* data;
if ((data = fopen("data.bin", "rb")) == NULL)
{
printf("Error opening file\n");
return 1;
}
struct Person* people;
fread(people, sizeof(struct Person) * 1/* Just read one person */, 1, data);
printf("%s\n", people[0].f_name);
fclose(data);
return 0;
}
Thanks for the help!
struct Person* people;
This allocates just a pointer to struct, but you don't have any allocated space for actual struct contents. Either use malloc similarly to your write program, or try something like:
struct Person people;
fread(&people, sizeof(people), 1, data);
You need to allocate memory for the person first. Change: struct Person* people; into struct Person* people = malloc(sizeof(struct Person));. And don't forget to free your memory at the end: free(people);.
You either need to malloc memory into the pointer variable people before you do the fread, or (easier) just read directly into a local variable:
struct Person people;
fread(&people, sizeof(struct Person) * 1/* Just read one person */, 1, data);
You need to allocate space for the data you are reading in:
people = malloc(sizeof(*people)*numPeople);
I'm trying read a file with this format instance|instruction...
like this 1 01 01 12 12 33, where the first number is the instance and after that is the numbers of the instruction.
Each line has it own id. so in that example that line if was the first one the id was 1, and the next line 2, and so on.
What I'm trying to do is group that information by a struct like the PCB struct I have. Each line has an id, and a queue where I store each number of the instruction part.
I have a struct where i have some variables and a queue inside it. The problem is the queue is not working.
typedef struct Queue
{
int sizeQueue;
int limit;
Node *head;
}Queue;
typedef struct PCB
{
int id;
int program_counter;
int size;
Queue pointer_instrucoes;
int instante;
}PCB;
typedef struct Node
{
PCB *element;
Node *next;
}Node;
And in the main I'm calling the struct with the queue to store some values.
PCB *p=new_pcb(contador);
....
p->pointer_instrucoes->head=atoi(s2); //s2 is the some number of the //instruction
but I'm getting this error:invalid type argument of '->'(have 'Queue {aka struct Queue}
MVCE:
main file
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //para o output
#include "queue2.h"
int le_ficheiro(char* filename) {
FILE *ficheiro=fopen(filename,"r");
size_t len=0;
char *line=NULL;
ssize_t read;
char *s1;//string antes do primeiro espaço
char *s2;//string depois do primeiro espaço
char *sp; //linha toda
if(ficheiro==NULL) {
exit(EXIT_FAILURE);
}
int contador=1; //onde comeca o id
while((read = getline (&line, &len,ficheiro))!=-1) //le de linha a linha
{
PCB *p=new_pcb(contador);
sp=strchr(line,' ');
if(!sp)
{
exit(EXIT_FAILURE);
}
s1=strndup(line,sp-line);
s2=sp+1;
p->instante=atoi(s1); //converte char to int
printf("Instante: %d\n",p->instante);
printf("Id: %d\n",p->id);
p.pointer_instrucoes.head=atoi(s2);
printf("%d\n",p->pointer_instrucoes->head);
printf("Retrieved line of length %zu:\n",read);
printf("%s\n",s2);
printf("Aqui : %c\n",line[0]);
contador++;
}
fclose(ficheiro);
if(line)
free(line);
free(s1);
exit(EXIT_SUCCESS);
}
int main()
{
char name[50];
printf("Name of the file: ");
scanf("%s",name);
le_ficheiro(name);
return 0;
}
queue2.h file
#include <stdbool.h>
typedef struct PCB PCB;
typedef struct Node Node;
typedef struct Queue Queue;
typedef struct Queue
{
int sizeQueue;
int limit;
Node *head;
}Queue;
typedef struct PCB
{
int id;
int program_counter;
int size;
Queue pointer_instrucoes;
int instante;
}PCB;
typedef struct Node
{
PCB *element;
Node *next;
}Node;
PCB * new_pcb(int id);
Node * new_node(PCB * e);
Queue * new_queue(int limit);
Queue2.c
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include "queue2.h"
Node * new_node(PCB * e)
{
Node *n=malloc(sizeof(Node));
n->element=e;
n->next=NULL;
return n;
}
Queue * new_queue(int limit)
{
Queue *q=malloc(sizeof(Queue));
q->limit=limit;
q->head=NULL;
q->sizeQueue=0;
return q;
}
PCB * new_pcb(int id)
{
PCB *p = malloc(sizeof(PCB));
p->id=id;
p->pointer_instrucoes=0;
p->program_counter=0;
p->size=0;
return p;
}
Example of input:
1 01 02 03 04 05
2 01 02 03 02 11
Your problems are rudimentary, and you need to spend time competing le_ficheiro. For starters, you cannot assign the result of atoi(s2) to p.pointer_instrucoes.head. head is not an int, it is a pointer to Node*. You violate the Strict Aliasing Rule C11 Standard - §6.5 Expressions (p6,7) and probably a dozen others in attempting to access and modify Node* by assigning an int as its value.
You invoke Undefined Behavior attempting to access p->id when it is indeterminate (uninitialized).
You make life much more difficult than it needs to be by attempting to manually separate values from line using strchr(line, ' '). You already have all values contained in line, you can use sscanf to parse all six values to int in a single call and validate the line, e.g.
while ((read = getline (&line, &len,ficheiro)) != -1) //le de linha a linha
{
int a, b, c, d, e, f;
if (sscanf (line, "%d %d %d %d %d %d",
&a, &b, &c, &d, &e, &f) != 6) {
fprintf (stderr, "error: failed to parse line '%d'.\n",
contador);
continue;
}
PCB *p = new_pcb (contador);
if (!p) /* Validate EVERY Allocation */
exit (EXIT_FAILURE);
However, before you can validate every allocation and avoid potentially invoking Undefined Behavior, you must provide meaningful return values from new_node, new_queue & new_pcb, to indicate success/failure, e.g.
Node *new_node (PCB *e)
{
Node *n = malloc (sizeof *n);
if (!n) { /* Validate EVERY Allocation */
perror ("malloc-new_node");
return NULL; /* return NULL on failure */
}
n->element = e;
n->next = NULL;
return n;
}
Queue *new_queue (int limit)
{
Queue *q = malloc (sizeof *q); /* typo in declaration */
if (!q) {
perror ("malloc-new_queue");
return NULL;
}
q->limit = limit;
q->head = NULL;
q->sizeQueue = 0;
return q;
}
PCB *new_pcb (int id)
{
PCB *p = malloc (sizeof *p);
if (!p) {
perror ("malloc-new_pcb");
return NULL;
}
p->id = id;
p->pointer_instrucoes = 0;
p->program_counter = 0;
p->size = 0;
return p;
}
It is clear you got part way through le_ficheiro and just gave up. It isn't anywhere near complete, only 1 of the data values from each line of input was even used in your code (the rest you attempted to print as text just to see where your s2 pointer was pointing -- but not make any further or meaningful use of the values)
You don't even call new_node in order to create a Node* value that conceivably could be assigned to p.pointer_instrucoes.head. Take it step-by-step. You need to call new_node somewhere in le_ficheiro so that you have a pointer you can assign to p.pointer_instrucoes.head. There isn't any magic to it, but you must be methodical about insuring each value and each member of each structure is created and properly initialized with a value before you attempt to use them.
Basically you had a shell for le_ficheiro which you need to continue to complete, working from a somewhat better starting position of:
int le_ficheiro (char* filename)
{
FILE *ficheiro = fopen (filename,"r");
size_t len = 0;
ssize_t read = 0;
int contador = 1; //onde comeca o id
if (ficheiro == NULL) {
perror ("fopen-filename");
exit (EXIT_FAILURE);
}
while ((read = getline (&line, &len,ficheiro)) != -1) //le de linha a linha
{
int a, b, c, d, e, f;
if (sscanf (line, "%d %d %d %d %d %d",
&a, &b, &c, &d, &e, &f) != 6) {
fprintf (stderr, "error: failed to parse line '%d'.\n",
contador);
continue;
}
PCB *p = new_pcb (contador);
if (!p)
exit (EXIT_FAILURE);
p->instante = a;
printf ("Instante: %d\n", p->instante);
/* you must assign and allocate as necessary to use remaining
* values read from file HERE. Nowhere do you assign p->id
* before attempting to print, etc...
*/
printf ("Id: %d\n", p->id);
/* you cannot assign atoi(s2) to p.pointer_instrucoes.head.
* it expects type 'Node *', not int.
*/
// p.pointer_instrucoes.head = FIXME;
// printf ("%d\n", p->pointer_instrucoes->head);
contador++;
}
fclose(ficheiro);
free (line);
free(s1);
exit(EXIT_SUCCESS);
}
When you are stuck in writing a function, don't give up. Instead see How to debug small programs and talk to the duck... Really, it helps :)
This is my code:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#define NAMESIZE 20
#define LINESIZE 1024
typedef struct name name;
struct name
{
char last[NAMESIZE]; /* last name */
char first[NAMESIZE]; /* first name*/
};
typedef struct record record;
struct record
{
name name;
int score;
};
typedef struct record_list record_list;
struct record_list
{
record *data; /* the dynamic array of records */
size_t nalloc; /* number of records allocated */
size_t nused; /* number of records in use */
};
void list_init(record_list *list)
{
list -> data = 0;
list -> nalloc = 0;
list -> nused = 0;
}
int list_insert(record_list *list, const record *rec)
{
size_t newSize;
record *tmp;
if(list -> nalloc == list -> nused)
{
if(list -> nalloc == 0)
{
newSize = 1;
}
else
{
newSize = 2 * list -> nalloc;
}
tmp = realloc(list -> data, newSize * sizeof(record));
if(tmp == 0)
{
return 0;
}
list -> data = tmp;
list -> nalloc = newSize;
}
list -> data[list -> nused++] = *rec;
return 1;
}
void list_destroy(record_list *list)
{
printf("Attempting Deletion");
free(list->data);
free(list->nalloc);
free(list->nused);
list -> data = 0;
list -> nalloc = 0;
list -> nused = 0;
}
int main(void){
record_list list;
record *r;
name n;
int score;
char input[NAMESIZE];
char name[NAMESIZE];
char lname[NAMESIZE];
list_init(&list);
while(input != NULL) {
printf("Please enter a value for Name: ");
scanf("%s", input);
strcpy(input, name);
printf("Enter last name: ");
scanf("%s", input);
strcpy(input, lname);
printf("Enter score: ");
scanf("%d", &score);
r=(record*)malloc(sizeof(record));
if(r == NULL){
printf("There isn't enough memory.\n");
}
strcpy(n.first, name);
strcpy(n.last, lname);
r -> name = n;
list_insert(&list, r);
printf("\n");
printf("Choose next action:\n");
printf("\tTo add more type \"add\";\n");
printf("\tTo delete all records type \"del\";\n");
scanf("%s", input);
if(strcmp(input, "del") == 0){
list_destroy(&list);
printf("Deleted");
break;
}
}
return 1;
}
I am working on a small lab exercise where we make a struct, fill it and clear it if the user needs to. Yesterday everything worked but today I seem to either have not saved it or broke something because I am getting a ton of errors.
Here is an example of the error I'm getting:
Essentially when I call a method
void list_destroy(record_list *list);
it crashes before reaching the first print statement which means I am doing something wrong with the method call.
Summarized question: What could be causing the segmentation fault (where am I accessing incorrect memory) Or how else can I clear my struct memory without using free?
Thank you very much.
This should tell what your problem is:
code.c: In function 'list_destroy':
code.c:74: warning: passing argument 1 of 'free' makes pointer from integer without a cast
code.c:75: warning: passing argument 1 of 'free' makes pointer from integer without a cast
You're trying to free int fields. You can't free them because they are not pointers to memory blocks.
So, remove these lines of code:
free(list->nalloc);
free(list->nused);
I have an array of structs I would like to write to a binary file. I have a write.c program and a read.c program. The write.c program seems to be working properly but when I run the read.c program I get a segmentation fault. I'm new to C so It would be great if someone could look over my code for any obvious errors. I promise it's not too long :)
write.c:
#include <stdlib.h>
#include <stdio.h>
struct Person
{
char f_name[256];
char l_name[256];
int age;
};
int main(int argc, char* argv[])
{
struct Person* people;
int people_count;
printf("How many people would you like to create: ");
scanf("%i", &people_count);
people = malloc(sizeof(struct Person) * people_count);
int n;
for (n = 0; n < people_count; n++)
{
printf("Person %i's First Name: ", n);
scanf("%s", people[n].f_name);
printf("Person %i's Last Name: ", n);
scanf("%s", people[n].l_name);
printf("Person %i's Age: ", n);
scanf("%i", &people[n].age);
}
FILE* data;
if ( (data = fopen("data.bin", "wb")) == NULL )
{
printf("Error opening file\n");
return 1;
}
fwrite(people, sizeof(struct Person) * people_count, 1, data);
fclose(data);
return 0;
}
read.c:
#include <stdlib.h>
#include <stdio.h>
struct Person
{
char f_name[256];
char l_name[256];
int age;
};
int main(int argc, char* argv[])
{
FILE* data;
if ((data = fopen("data.bin", "rb")) == NULL)
{
printf("Error opening file\n");
return 1;
}
struct Person* people;
fread(people, sizeof(struct Person) * 1/* Just read one person */, 1, data);
printf("%s\n", people[0].f_name);
fclose(data);
return 0;
}
Thanks for the help!
struct Person* people;
This allocates just a pointer to struct, but you don't have any allocated space for actual struct contents. Either use malloc similarly to your write program, or try something like:
struct Person people;
fread(&people, sizeof(people), 1, data);
You need to allocate memory for the person first. Change: struct Person* people; into struct Person* people = malloc(sizeof(struct Person));. And don't forget to free your memory at the end: free(people);.
You either need to malloc memory into the pointer variable people before you do the fread, or (easier) just read directly into a local variable:
struct Person people;
fread(&people, sizeof(struct Person) * 1/* Just read one person */, 1, data);
You need to allocate space for the data you are reading in:
people = malloc(sizeof(*people)*numPeople);