#include <stdio.h>
#include <stdlib.h>
struct birdhome{
int area;
int heightcm;
int feederquantity;
char hasNest[6];
};
struct bird{
char isRinged[6];
char nameSpecies[50];
int birdAgeMonths;
struct BirdHome *hom;
char gender[7];
};
int save(char * filename, struct bird *st, int n);
int load(char * filename);
int main(void)
{
char * filename = "birds.dat";
struct bird birds[] = { "True","sparrow",3,10,20,2,"False","Male","False","crane",24,50,100,6,"True","Female","False","False","griffin",10,100,80,1,"False","Male" };
int n = sizeof(struct bird) / sizeof(birds[0]);
save(filename, birds, n);
load(filename);
return 0;
}
int save(char * filename, struct bird * st, int n)
{
FILE * fp;
char *c;
int size = n * sizeof(struct bird);
if ((fp = fopen(filename, "wb")) == NULL)
{
perror("Error occured while opening file");
return 1;
}
c = (char *)&n;
for (int i = 0; i<sizeof(int); i++)
{
putc(*c++, fp);
}
c = (char *)st;
for (int i = 0; i < size; i++)
{
putc(*c, fp);
c++;
}
fclose(fp);
return 0;
}
int load(char * filename){
FILE * fp;
char *c;
int m = sizeof(int);
int n, i;
int *pti = (int *)malloc(m);
if ((fp = fopen(filename, "r")) == NULL)
{
perror("Error occured while opening file");
return 1;
}
c = (char *)pti;
while (m>0)
{
i = getc(fp);
if (i == EOF) break;
*c = i;
c++;
m--;
}
n = *pti;
struct bird * ptr = (struct bird *) malloc(n * sizeof(struct bird));
c = (char *)ptr;
while ((i= getc(fp))!=EOF)
{
*c = i;
c++;
}
printf("\n%d birds in the file stored\n\n", n);
for (int k = 0; k<n; k++)
{
printf("%-10d %-6s %-50s %-24d %-100d %-100d %-10d %-10s %-10s \n", k + 1, (ptr + k)->isRinged, (ptr + k)->nameSpecies,(ptr + k)->birdAgeMonths,(ptr + k)->hom.area,(ptr + k)->hom.heightcm,(ptr + k)->hom.feederquantity,(ptr + k)->hom.hasNest,(ptr + k)->gender);
}
Well, the program is theoretically running. The problem is with the printf inside the load function.
The error says that all the structure types that come in struct Birdhome is a
pointer and that I should use -> instead of . in it.
But when I do this it says that I should change the . to ->.
The problem is that bird.hom is a pointer. Saving a pointer to a file is not a useful thing to do, because memory addresses change from one process to another. It's also not saving the contents of the BirdHome structure. And your initialization of birds doesn't work, because you can't initialize members of an indirect structure as part of the main structure.
You should declare it as an embedded structure rather than a pointer.
struct bird{
char isRinged[6];
char nameSpecies[50];
int birdAgeMonths;
struct BirdHome hom;
char gender[7];
};
Declaring it as a pointer would be useful if you wanted a dynamically-sized array of homes, or you wanted to allow multiple birds to reference the same BirdHome structure. If that's what you really need, you'll need to redesign your save and load functions so they dereference the pointer and save what it points to. And if you have a dynamically-sized array of BirdHome, you need to include the array size in bird.
Other errors in your code:
You have an extra "False" in the initialization list of birds. It should be:
struct bird birds[] = { "True","sparrow",3,10,20,2,"False","Male","False","crane",24,50,100,6,"True","Female","False","griffin",10,100,80,1,"False","Male" };
Your calculation of n is incorrect. It should be:
int n = sizeof(birds) / sizeof(birds[0]);
Related
I have the following struct:
typedef struct employee
{
int name_length;
char* name;
float salary;
} Employee;
and the following functions:
Employee** makeArr(char* fileName, int* size)
{
FILE* f = fopen(fileName, "rb");
checkOpenFile(f);
Employee** arr = (Employee**)malloc(sizeof(Employee*));
checkAllocation(&arr);
int counter = 0;
while (!feof(f))
{
int employeeNameSize;
float employeeSalary;
fread(&employeeNameSize, sizeof(int), 1, f);
if (feof(f))
break;
char* employeeName = (char*)malloc(sizeof(char) * employeeNameSize+1);
checkAllocation(&employeeName);
fread(employeeName, sizeof(char), employeeNameSize, f);
employeeName[employeeNameSize] = '\0';
fread(&employeeSalary, sizeof(float), 1, f);
arr[counter] = makeEmployee(employeeNameSize, employeeName, employeeSalary);
counter++;
realloc(arr, sizeof(Employee*)*(counter));
}
*size = counter;
fclose(f);
return arr;
}
and:
void freeEmployeeArr(Employee** arr, int size)
{
for(int i = 0; i < size; i++)
{
free(arr[i]->name);
free(arr[i]);
}
free(arr);
}
and this:
Employee* makeEmployee(int nameLength, char* name, float salary)
{
Employee* tmp = (Employee*)malloc(sizeof(Employee));
checkAllocation(&tmp);
tmp->name_length = nameLength;
tmp->name = name;
tmp->salary = salary;
return tmp;
}
my main:
void main(int argc, char* argv[])
{
char* name1 = argv[1];
char* name2 = argv[2];
int size;
Employee** ans = makeArr(name1, &size);
freeEmployeeArr(ans, size);
}
The problem that I encounter:
free(arr);
crashes my program. If I remove this line, everything works fine.
But this specific causes me some problems.
If I'm trying to start without debugging, I get this message:
and if I'm debugging, I get this message:
I really have no idea what's wrong with my program. I've read that these kind of problems might appear when I realloc/malloc with a value of zero. But this is not the case.
Can anyone spot my mistake here?
Thanks in advance.
The line
realloc(arr, sizeof(Employee*)*(counter));
is bad. You have to assign the new pointer returned to arr.
It should be like this:
Employee** newArr = realloc(arr, sizeof(Employee*)*(counter));
if (newArr == NULL) {
/* handle error, clean up and return from the function */
}
arr = newArr;
I have an array structs that hold char names. I want to sort them alphabetically using qsort however I keep getting an error message saying "initialization discards ‘const’ qualifier from pointer target type". I believe my cmpmi() function and qsort arguments are correct. Any help is greatly appreciated!
My error is:
gcc -std=gnu11 -Werror -Wall -o main main.c -lm -g
main.c: In function ‘compmi’:
main.c:18:25: error: initialization discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
const student_t **p1 = a;
^
main.c:19:25: error: initialization discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
const student_t **p2 = b;
^
cc1: all warnings being treated as errors
makefile:2: recipe for target 'main' failed
make: *** [main] Error 1
This is my qsort function:
int compmi(const void *a, const void *b)
{
const student_t **p1 = a;
const student_t **p2 = b;
return strcmp((*p1)->name, (*p2)->name);
}
Code:
int main(int argc, char **argv) {
unsigned numrecords;
int i = 0;
int length_multiplier = 1;
char *lettergrade;
//char *input = NULL;
//char *pItem;
student_t **students = NULL;
// OPENS THE FILE IN BINARY
FILE *input_file;
input_file = fopen("input.bin", "rb");
// READS THE NUMBER OF RECORDS
fread(&numrecords, sizeof(u_int32_t), 1, input_file);
// LOOPING THROUGH EACH ENTRY
for(i = 0; i <= numrecords; i++)
{
// ALLOCATES MEMORY
students = realloc(students, sizeof(student_t *) * length_multiplier);
students[i] = malloc(sizeof(student_t));
students[i]->name = malloc(sizeof(student_t)* 20);
fread(students[i]->name, sizeof(student_t), 20, input_file);//READ NAME
fread(&students[i]->gpa, sizeof(student_t), 1, input_file); // READ GPA
fread(&students[i]->age, sizeof(u_int32_t), 1, input_file);// READ AGE
length_multiplier++;
}
//SORTING WITH QSORT
qsort(*students, numrecords, sizeof(student_t *), compmi);
// PRINTING OUTPUT
for(i = 0; i < length_multiplier - 2 ; i++)
{
printf("%i of %d:\n", i + 1, numrecords);
printf("Name: %s\n", students[i]->name);
//printf("UPDATED GPA USE THIS: %.1f\n", students[i]->gpa);
printf("GPA: %.1f \n", students[i]->gpa);
printf("Age: %i\n", students[i]->age);
printf("\n");
}
// FREEING MEMORY
for(i = 0; i < length_multiplier; i++)
{
free(students[i]);
}
free(students);
fclose(input_file);
return 0;
}
The variable a points to a const qualified type, but p1 does not point to a const type (but what that points to is). You need to add const between the *s.
int compmi(const void *a, const void *b)
{
const student_t * const *p1 = a;
const student_t * const *p2 = b;
return strcmp((*p1)->name, (*p2)->name);
}
There are multiple problems in the code:
the comparison function converts pointers to constant objects to pointers to non constant objects themselves pointers to constant student objects. The original constness is not preserved. The definitions should be:
const student_t * const *p1 = a;
const student_t * const *p2 = b;
the reading loop should stop when i == numrecords so you should use i < numrecords instead of i <= numrecords.
the fread sizes are incorrect: you should specify the size of the member type, not that of the student_t structure.
you pass *students to qsort instead of the array pointer students.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct student_t {
char *name;
float gpa;
int age;
} student_t;
int compmi(const void *a, const void *b) {
const student_t * const *p1 = a;
const student_t * const *p2 = b;
return strcmp((*p1)->name, (*p2)->name);
}
int main(int argc, char **argv) {
unsigned numrecords;
int i = 0;
char *lettergrade;
// OPENS THE FILE IN BINARY
FILE *input_file = fopen("input.bin", "rb");
if (input_file == NULL) {
fprintf(stderr, "cannot open input.bin\n");
return 1;
}
// READS THE NUMBER OF RECORDS
fread(&numrecords, sizeof(unsigned), 1, input_file);
// allocate the array directly, no need for realloc
student_t **students = malloc(sizeof(*students) * num_records);
if (students == NULL) {
fprintf(stderr, "allocation error\n");
return 1;
}
// LOOPING THROUGH EACH ENTRY
for (i = 0; i < numrecords; i++) {
// ALLOCATE MEMORY
if ((students[i] = malloc(sizeof(student_t))) == NULL
|| (students[i]->name = calloc(21, 1)) == NULL) {
fprintf(stderr, "allocation error\n");
return 1;
}
// READ NAME, GPA and AGE
if (fread(students[i]->name, 20, 1, input_file) != 1
|| fread(&students[i]->gpa, sizeof(students[i]->gpa), 1, input_file) != 1
|| fread(&students[i]->age, sizeof(students[i]->age), 1, input_file) != 1) {
fprintf(stderr, "error reading data for record %d / %d\n", i + 1, numrecords);
return 1;
}
}
fclose(input_file);
//SORTING WITH QSORT
qsort(students, numrecords, sizeof(*students), compmi);
// PRINTING OUTPUT
for (i = 0; i < numrecords; i++) {
printf("%i of %d:\n", i + 1, numrecords);
printf("Name: %s\n", students[i]->name);
//printf("UPDATED GPA USE THIS: %.1f\n", students[i]->gpa);
printf("GPA: %.1f\n", students[i]->gpa);
printf("Age: %i\n", students[i]->age);
printf("\n");
}
// FREEING MEMORY
for (i = 0; i < numrecords; i++) {
free(students[i]->name);
free(students[i]);
}
free(students);
return 0;
}
Note however that using binary format for the data is problematic:
the sizes and representation of various types may change from one system to another.
binary files require a precise specification and are not easy to debug.
text files are a preferred format for interchange. They are easy to read and write.
There is a specific csv file containing lines in a specific format, and I defined a struct of it.
typedef struct {
int passengerId;
int survival; // survived = 1, dead = 0
enum PClass pclass; // 1st, 2nd, 3rd class
char* name;
enum Sex sex;
float age;
int sibsp; //number of siblings
int parch; //number of family members
char* ticket; //ticket number
double fare;
char* cabin;
char* embarked;
}SUVData;
and this struct is declared in main() with a double pointer format, initial size 1 - for implementation of 2-dimensional array :
int main() {
SUVData** data = (SUVData**)calloc(1, sizeof(SUVData*));
ReadData(data, "titanic.csv");
return 0;
}
and this is given as a parameter to the reading data function :
void ReadData(SUVData** dataset, char* filename) {
FILE* fp;
char line[1024];
int i = 0;
// temporary variables
int tempPassengerId;
int tempSurvival;
int tempPClass;
char* tempName = (char*)malloc(sizeof(char) * 100);
char* tempSex = (char*)malloc(sizeof(char) * 7);
float tempAge;
int tempSibsp;
int tempParch;
char* tempTicket = (char*)malloc(sizeof(char) * 20);
double tempFare;
char* tempCabin = (char*)malloc(sizeof(char) * 10);
char* tempEmbarked = (char*)malloc(sizeof(char) * 2);
fp = fopen(filename, "r");
if (fp == NULL) {
printf("file open error\n");
return;
}
printf("\nFile loaded\n");
while (fgets(line, 1024, fp)) {
line[strlen(line) - 1] = '\0';
printf("test line : %s\n", line);
// Format in temp variables
int t = sscanf(line, "%d,%d,%d,%[^,],%[^,],%f,%d,%d,%[^,],%lf,%[^,],%s", &tempPassengerId, &tempSurvival, &tempPClass, tempName, tempSex, &tempAge, &tempSibsp, &tempParch,
tempTicket, &tempFare, tempCabin, tempEmbarked);
// Re-arrange in dataset (where I'm having problem)
(*(*(dataset + i))).passengerId = tempPassengerId;
printf("test Id : %d\n", (*(*(dataset + i))).passengerId);
i++;
}
fclose(fp);
}
I was planning on assigning temporary variables inside struct SUVData, using code like this(as written above) : (*(*(dataset + i))).passengerId = tempPassengerId;
Tried to test if it's working, but no.
Here is my problem: I have to make this program for school and I spent the last hour debugging and googling and haven't found an answer.
I have an array of structures in my main and I want to give that array to my function seteverythingup (by call by reference) because in this function a string I read from a file is split up, and I want to write it into the structure but I always get a SIGSEV error when strcpy with the struct array.
This is my main:
int main(int argc, char *argv[])
{
FILE* datei;
int size = 10;
int used = 0;
char line[1000];
struct raeume *arr = (raeume *) malloc(size * sizeof(raeume*));
if(arr == NULL){
return 0;
}
if(argc < 2){
return 0;
}
datei = fopen(argv[1], "rt");
if(datei == NULL){
return 0;
}
fgets(line,sizeof(line),datei);
while(fgets(line,sizeof(line),datei)){
int l = strlen(line);
if(line[l-1] == '\n'){
line[l-1] = '\0';
}
seteverythingup(&line,arr,size,&used);
}
ausgabeunsortiert(arr,size);
fclose(datei);
return 0;
}
and this is my function:
void seteverythingup(char line[],struct raeume *arr[], int size,int used)
{
char *token,raumnummer[5],klasse[6];
int tische = 0;
const char c[2] = ";";
int i=0;
token = strtok(line, c);
strcpy(raumnummer,token);
while(token != NULL )
{
token = strtok(NULL, c);
if(i==0){
strcpy(klasse,token);
}else if(i==1){
sscanf(token,"%d",&tische);
}
i++;
}
managesize(&arr[size],&size,used);
strcpy(arr[used]->number,raumnummer);
strcpy(arr[used]->klasse,klasse);
arr[used]->tische = tische;
used++;
}
Edit: Since there is more confusion I wrote a short program that works out the part you are having trouble with.
#include <cstdlib>
struct raeume {
int foo;
int bar;
};
void seteverythingup(struct raeume *arr, size_t len) {
for (size_t i = 0; i < len; ++i) {
arr[i].foo = 42;
arr[i].bar = 53;
}
}
int main() {
const size_t size = 10;
struct raeume *arr = (struct raeume*) malloc(size * sizeof(struct raeume));
seteverythingup(arr, size);
return 0;
}
So basically the signature of your functions is somewhat odd. Malloc returns you a pointer to a memory location. So you really dont need a pointer to an array. Just pass the function the pointer you got from malloc and the function will be able to manipulate that region.
Original Answer:
malloc(size * sizeof(raeume*));
This is probably the part of the code that gives you a hard time. sizeof returns the size of a type. You ask sizeof how many bytes a pointer to you raeume struct requires. what you probably wanted to do is ask for the size of the struct itself and allocate size times space for that. So the correct call to malloc would be:
malloc(size * sizeof(struct raeume));
I've the following code :
int parser_start(t_control *shell)
{
int i;
int c;
int count;
int separator;
count = 0;
shell->command_index = 1;
shell->commands = malloc(parser_count_separators(shell));
shell->commands[count] = malloc(sizeof(shell->commands));
shell->commands[count]->command = malloc(my_strlen(shell->cli) * sizeof(char));
shell->commands[count]->op = 0;
i = 0;
c = 0;
while (shell->cli[i] != '\0')
{
separator = parser_is_separator(shell->cli[i], shell->cli[i + 1]);
if (separator == -1)
shell->commands[count]->command[c++] = shell->cli[i];
else
{
shell->command_index++;
count++;
shell->commands[count] = malloc(sizeof(shell->commands));
shell->commands[count]->command = malloc(my_strlen(shell->cli) * sizeof(char));
shell->commands[count]->op = separator;
my_printf("%d\n", shell->commands[count]->op);
c = 0;
}
i = i + parser_separator_get_size(separator);
}
}
With the following struct :
typedef struct s_command
{
char *command;
char *program;
char **argv;
int argc;
pid_t pid;
int op;
} t_command;
typedef struct s_control
{
pid_t pid;
char **env;
char **path;
char *cli;
int fd_history;
int power;
int pipefd[2];
int command_index;
char **builtins;
int (*builtins_fptr[6])(struct s_control *, int );
t_command **commands;
} t_control;
When I dump shell->commands[count]->op with my printf, it print 1 as I want.
When I dump the same emplacement in another function I got 7564320.
Why ? Does my op field needs to be malloc too?
Thanks
While it is hard to tell without seeing more code, the most likely culprit is:
shell->commands = malloc(parser_count_separators(shell));
It's clear that the commands field of the t_control structure is a pointer. Without seeing the code for parser_count_separators, it is hard to know for certain, but it seems reasonable that parser_count_separators(shell) will return a count of separators, and that the size of commands should be either
parser_count_separators(shell) * sizeof *shell->commands)
or
(parser_count_separators(shell) + 1) * sizeof *shell->commands)
depending on whether parser_count_separators actually counts separators as its name implies, or counts subcommands (which is one more than the number of separators).