C write struct to file - c

I am trying to save struct data to file. I saved the data this way.
node_trx * trx_list;
trx_list = calloc(1, sizeof(node_trx *));
trx_list->amount = "123123123";
trx_list->currency = 123;
trx_list->next_node = NULL;
if (1 != fwrite(trx_list, length, 1, f)) {
//error
}
free(trx_list);
Here is my struct:
typedef struct {
char amount;
int currency;
struct node_trx * next_node; } node_trx;
Main problem is after i saved struct to file and then after read, when print values, it is printing wrong values. For example: i stored currency as 123, then printed 6788576 this kind of numbers.
here is my reading code:
int read_last_trx_from_file (const char * file_name, node_trx * * trx, unsigned * trx_len)
{
FILE * f;
*trx = NULL;
if (NULL == (f = fopen(tools_get_full_filename_const(file_name), "rb")))
{
return 2; //error
}
size_t fsize;
fseek(f, 0, SEEK_END);
fsize = ftell(f);
fprintf(stdout, "file size: %zd\n", fsize);
if (!fsize)
{
fclose(f);
return 3; //no data
} else {
if (fsize == 1) {
return 3; // no data
}
}
rewind(f);
if (NULL != (*trx = (node_trx *) calloc(1, fsize)))
{
if (1 != fread(*trx, fsize, 1, f))
{
fclose(f);
free(*trx);
return 2; //error
}
}
fclose(f);
*trx_len = fsize;
return 0; //OK }
Main function that calls read function:
int display_trx() {
node_trx * card_data;
if (3 != read_last_trx_from_file(LAST_TRX_OBJECT, &card_data, &data_set_len)) {
if (card_data != NULL) {
printf("%s AMOUNT \n", card_data->amount);
printf("%d CURRENCY \n", &card_data->currency);
}
}
}
After i read this way , when i print amount data, segmentation fault error occurs. so why segment error occured?
And when i print currency, it printing 734364636 this kinda numbers. So why it prints wrong numbers.
Or i only wrote pointer of struct to file?
Please help me guys.

There are two obvious errors in your code.
In struct declaration, the type of amount is char, but when you initialize it in trx_list->amount = "123123123";, you assigned a string, or char[10] array (there is an extra one for NULL terminator).
In function display_trx, second printf, the result of &card_data->currency is int *, not int. If you want to print out currency, why don't follow the first print, use card_data->currency (without &)? You get that large number because you are printing pointer value implicitly converted into int, or the address of currency in card_data.
And there is one error which compiler will not warn you (because it is not syntactically wrong.). As BLUEPIXY said in the comments, when allocating and initializing trx_list, you should really use calloc(1, sizeof(node_trx)). You are allocating space for what pointer trx_list points to, not the pointer itself, so there should not be an asterisk in sizeof.
My suggestion is using a "smart" compiler, such as gcc, and enable warnings. This is a good practice (at least for me). Thank you!

Related

Save struct with pointer members in file

I'm trying to save a struct into a .dat file and read it back in later.
struct myStruct{
char **one;
mytype **two;
mytype2 *three;
}
With an assigning function:
struct MyStruct get_struct() = {
char **pi = ...;
mytype **pa = ...;
mytype2 **po = ...;
MyStruct n = {pi, pa, po};
return n;
}
I originally tried to save this struct into a .dat file by doing this:
struct MyStruct s = get_struct();
myoutfile = fopen("file.dat", "w");
if (myoutfile == NULL) {
fprintf(stderr, "\nError opend file\n");
exit(1);
}
fwrite(&s, sizeof(struct MyStruct), 1, myoutfile);
fclose(myoutfile);
and read it back in with:
fread(&t, sizeof(struct MyStruct), 1, myinfile)
Now I learned, that this does not work (segmentation error), because I only save the location where the pointer points to, not the actual thing.
Now my question is, how can I do it properly? I have found some solutions for C++ but I need to stay in C.
EDIT:
Later on, I want to call a function which looks like this:
void work_with_struct(MyStruct s){
char ** xone = s.one;
mytype **xtwo = s.two;
mytype2 *xthree = s.three;
}
This post is related to this post, but as I could specify my mistake now, asking in a new post makes more sense to me.
As always in programming, you break up the task to smaller chunks, and break up smaller chunks to yet smaller chunks, until every chunk is easy.
int saveMyStruct (struct myStruct* myStruct, FILE* file) {
// what do I do here?!?!
// well it has three members
// so treat each one in sequence
int result;
result = saveStringArray(myStruct->one, file);
if (result >= 0)
result = saveMyTypeArray (myStruct->two, file);
if (result >= 0)
result = saveMyType (myStruct->three, file);
return result;
}
Note how the status is checked all the time. If you work with files, you need to check the status all the time.
What next? You need to write three functions mentioned above.
saveStringArray(char** stringArray, FILE* file)
{
// first save the length of the array, then save each individual string
int length = getStringArrayLength(stringArray);
int result = fwrite(&length, sizeof(length), 1, file);
if (result != 1)
return -1;
for (i = 0; i < length; ++i)
{
result = saveString(stringArray[i], file);
if (result < 0)
return -1;
}
return i;
}
And so on and so forth. I presume your array of pointers is NULL-terminated; if not, you need to have some other way to know its length.
Note how array length is always saved before array elements. This is because you will need to read your array later, and you will need to know where to stop. It will also be easy to allocate your array when you read it.

C : Realloc doesn't work with dynamic double pointer array

I am facing some issues regarding a realloc with a double pointer dynamic array.
What I would like to perform is to add 2 pointers of type Flight* inside the array schedule of type Flight **.
For that, I am relying on the function add_flight in the Functions.c file.
This function asks the user for the airline and flight number values and stores these data in a new Flight* f. If the schedule is null (no flight yet added) it allocates memory for the newly created flight otherwise it realloc the size of schedule in order the add the new flight.
Main.c file:
int main() {
int choice = 1;
Flight** schedule = NULL;
printf("---AIRPORT MANAGER---");
schedule = add_flight(schedule);
printf("\n%s : %d\n", (*schedule)->airline, (*schedule)->flightNumber);
schedule = add_flight(schedule);
printf("\n%s : %d\n", (*schedule + 1)->airline, (*schedule)->flightNumber);
return 0;
}
Functions.c file :
#include "Functions.h"
void mygets(char* s, int maxLength) {
fflush(stdout);
if (fgets(s, maxLength, stdin) != NULL) {
size_t lastIndex = strlen(s) - 1;
if (s[lastIndex] == '\n')
s[lastIndex] = '\0';
}
}
void flush() {
char buffer;
while ((buffer = getchar()) != EOF && buffer != '\n');
}
Flight** add_flight(Flight** schedule) {
Flight* f;
char buffer[100];
if ((f = (Flight*)malloc(sizeof(Flight*))) == NULL) {
exit(1);
}
printf("\n\n---FLIGHT CREATION---");
printf("\nAirline: ");
mygets(buffer, sizeof(buffer));
if ((f->airline = _strdup(buffer)) == NULL) {
exit(1);
}
memset(buffer, 0, 100);
printf("\nFlight number: ");
scanf("%d", &f->flightNumber);
flush();
if (schedule == NULL) {
if ((schedule = malloc(sizeof(Flight*))) == NULL) {
exit(1);
}
*schedule = f;
}
else {
int numberFlights = ((sizeof(*schedule)) / 4) + 1;
if ((schedule = realloc(schedule, numberFlights * sizeof(Flight*))) == NULL) {
exit(1);
}
*(schedule + numberFlights -1) = f;
}
return schedule;
}
The issue comes when the second call of add_flight is performed in the main.c
In the add_flight function, the data are indeed stored in the new Flight* f and then the else statement is considered: the variable numberFlights gets the value 2. However, the realloc doesn't work, the schedule is not enlarged and thus there is still only the first flight stored inside this schedule array. I can't figure out why the second flight is not added inside the schedule.
Can someone explain me why this realloc fails ?
Thanks for your help :)
The sizeof operator is evaluated at compile time. It cannot be used to determine the size of a dynamically allocated array.
C imposes the burden of keeping track of the actual size of an array onto the programmer. You could kee a separate count variable, but because the actual array and its size belong together, it is useful to store them alongside each other in a struct:
typedef struct Flight Flight;
typedef struct Flights Flights;
struct Flight {
char airline[4];
int number;
char dest[4];
};
struct Flights {
Flight *flight;
int count;
};
Instead of operating on the array, operate on the struct:
void add_flight(Flights *fl,
const char *airline, int number, const char *dest)
{
int n = fl->count++; // n is old count; fl->count is new count
fl->flight = realloc(fl->flight,
(fl->count + 1) * sizeof(*fl->flight));
snprintf(fl->flight[n].airline, 4, "%s", airline);
snprintf(fl->flight[n].dest, 4, "%s", dest);
fl->flight[n].number = number;
}
Intialize the flights struct with NULL and a count of zero and don't forget to release the used memory when you're done:
int main(void)
{
Flights fl = {NULL, 0};
add_flight(&fl, "AF", 5512, "CDG");
add_flight(&fl, "AA", 1100, "ATL");
add_flight(&fl, "LH", 6537, "FRA");
add_flight(&fl, "BA", 8821, "LHR");
add_flight(&fl, "IB", 1081, "EZE");
print_flights(&fl);
free(fl.flight);
return 0;
}
You can see it in action here. Some observations:
There is no need to distinguish between adding the first and subsequent flights, because realloc(NULL, size) behaves exactly like malloc(size).
It is not very efficient to reallocate the memory for each added item. Instead, you pick a suitable initial array size like 4 or 8, then double the size when you hit the limit. That means that the allocated size and the count may differ and you need an aditional memsize field in your flights struct.
The code above relies on manual initialization and destruction. Usually, you will write "constructor" and "destructor" functions to do that for you.

Convert/compare an integer to a string in C and error in a 'for' cycle

I have this piece of code, that doesn't work like it should. This function is connected with another one, where I ask for a city and a date. Then, after confirming both exist in the file, this function calls this new one, down below.
I know I can't compare a string with an integer, I know that is possible to convert in one another, but I don't know how to do it and if I can do it in this case. id is an integer, and meteo_city_id is a string present in a struct. I have this problem in the second part of the condition in the if inside the for.
At the same time, in the same for, I have i < 152. This is the number of rows that exist in a file I have to use. However, the user can add lines in the file so, after adding a new one, that code doesn't work anymore. So what can I replace 152 so that cycle for works, regardless of the number of rows that are added later?
Thanks for the help. Here is the function:
#define TAM_STR 100
typedef struct city_t{
char city_id[TAM_STR];
char city_name[TAM_STR];
char county_name[TAM_STR];
char district_name[TAM_STR];} city_t;
typedef struct meteo_t{
char meteo_id[TAM_STR];
char meteo_city_id[TAM_STR];
char tempt_max[TAM_STR];
char tempt_min[TAM_STR];
char humidity[TAM_STR];
char pressure[TAM_STR];
char date[11];} meteo_t;
city_t *read_meteo(const char *filename, size_t *len)
{
if(filename == NULL || len == NULL)
return NULL;
FILE *fp = fopen(filename, "r");
if(fp == NULL)
{
fprintf(stderr, "Could not open %s: %s\n", "meteo.csv", strerror(errno));
return NULL;
}
meteo_t *arr = NULL, *tmp;
*len = 0;
char line[1024];
while(fgets(line, sizeof line, fp))
{
tmp = realloc(arr, (*len + 1) * sizeof *arr);
if(tmp == NULL)
{
fprintf(stderr, "could not parse the whole file %s\n", "meteorologia.csv");
if(*len == 0)
{
free(arr);
arr = NULL;
}
return arr;
}
arr = tmp;
sscanf(line, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%s", (arr[*len].meteo_id), (arr[*len].meteo_city_id), (arr[*len].tempt_max), (arr[*len].tempt_min), (arr[*len].humidity), (arr[*len].preassure), (arr[*len].date));
(*len)++;
}
fclose(fp);
if(*len == 0)
{
free(arr);
arr = NULL;
}
return arr;
}
void search_meteo_by_city_by_date(meteo_t *meteo, size_t len, const char *city, const int id, const char *date){
bool find = false;
if(meteo == NULL || city == NULL || id == NULL || date == NULL) {
printf("ERROR");
}
for(size_t i = 0; i < 152; ++i) {
if (strcasecmp(date, meteo[i].date) == 0 && id == meteo[i].meteo_city_id) {
find = true;
printf("Information for: %s in %s \nMaximum Temperature: %s ºC\nMinimum Temperature: %s ºC\nHumidity: %s \nPressure: %s hPa\n\n\n", city, date, meteo[i].tempt_max, meteo[i].tempt_min, meteo[i].humidity, meteo[i].preassure);
}
}
if(find == false) {
printf("No results were found for: %s\n", city);
}
}
void search_date_by_city() {
size_t cities_len;
city_t *cities = read_cities("cities.csv", &cities_len);
char local[100];
char date[100];
// error
if(cities == NULL) {
printf("ERROR");
}
printf("City: ");
scanf("%[^\n]%*c", local);
int id = search_for_city_by_name(cities, &cities_len, cidade);
if(id == -1) {
printf("That city doesn't exist\n");
return;
}
printf("Date: ");
scanf("%[^\n]%*c", date);
size_t meteo_len;
meteo_t *meteo = read_meteo("meteo.csv", &meteo_len);
if(meteo == NULL) {
printf("ERROR");
}
search_meteo_by_city_by_date(meteo, &meteo_len, local, id, date);
}
The file cities.csv has 152 rows and 4 columns, such as
id,city,county,district
The file meteo.csv has 152 rows and 7 cloumns, such as
meteo_id,meteo_city_id,tempt_max,tempt_min,humidity,pressure,date
the function: search_meteo_by_city_by_date() is expecting the parameter len to contain the actual number of entries, However, where that function is being called, what is being passed is the ADDRESS of the variable that contains the actual number of entries.
Suggest replace this:
search_meteo_by_city_by_date(meteo, &meteo_len, local, id, date);
with this:
search_meteo_by_city_by_date(meteo, meteo_len, local, id, date);
which is passing the contents of metro_len rather than the address of metro_len
then replace this:
for(size_t i = 0; i < 152; ++i)
with
for(size_t i = 0; i < len; ++i)
So you need to know the number of lines in a file. Can you simply count the number of line feeds or carriage returns ?
I can’t see your implementation of read_meteo but I presume you can add something in there that counts the number of lines in the file.
Also, atoi() might be useful to convert a string number to an int.
The larger solution
Always compile with all warnings enabled.
If you had done so, you would have caught things like these:
In function ‘read_meteo’:
test.c:51:16: warning: return from incompatible pointer type [-Wincompatible-pointer-types]
return arr;
^~~
error: ‘meteo_t {aka struct meteo_t}’ has no member named ‘preassure’;
did you mean ‘pressure’?
sscanf(line, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%s",
(arr[*len].meteo_id), (arr[*len].meteo_city_id), (arr[*len].tempt_max),
(arr[*len].tempt_min), (arr[*len].humidity), (arr[*len].preassure),
(arr[*len].date));
warning: comparison between pointer and integer
if (strcasecmp(date, meteo[i].date) == 0 && id == meteo[i].meteo_city_id) {
^~
warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
meteo_t *meteo = read_meteo("meteo.csv", &meteo_len);
^~~~~~~~~~
warning: passing argument 2 of ‘search_meteo_by_city_by_date’
makes integer from pointer without a cast [-Wint-conversion]
search_meteo_by_city_by_date(meteo, &meteo_len, local, id, date);
^~~~~~~~~~
note: expected ‘size_t {aka long unsigned int}’ but argument
is of type ‘size_t * {aka long unsigned int *}’
void search_meteo_by_city_by_date(meteo_t *meteo, size_t len,
^~~~~~~~~~~
const char *city, const int id, const char *date){
The not-so-right-after-all solution
Simply replace 152 with len. Apparently you already have an array index counter in there:
meteo_t *meteo = read_meteo("meteo.csv", &meteo_len);
if (meteo == NULL) {
printf("ERROR");
// YOU SHOULD ALSO EXIT IF YOU EVER ENTER HERE.
}
search_meteo_by_city_by_date(meteo, &meteo_len, cidade, id, date);
The above, as #user3629249 pointed out, is logically correct but formally incorrect because the parameter being passed is not the value (which is probably 152, so correct) but its address, which is almost surely NOT 152, and therefore wildly incorrect. And that's why when you apply this solution you get a crash.
If you had activated compiler warnings, this error wouldn't have been there, and if I had, I believe I would have given the right (but still not complete! Look at those problems above!) answer. Since neither of us used warnings, you and I both ended up being wrong. So: use compiler warnings.

Segmentation Fault(core dumped) - Structure;

So I have the following question:
I have this struct ListAut
struct ListAut{
char* biggestn;
int sizeof_biggestn;
int total_len;
struct node* avl;
};
Its typedef is as it follows:
typedef struct ListAut *IndexOfAuts;
IndexOfAuts *newIndexOfAuts()
{
int i;
IndexOfAuts *ioa = malloc(27 * sizeof(struct ListAut));
for (i = 0; i < 27; i++)
{
ioa[i]->biggestn = "";
ioa[i]->sizeof_biggestn = 0;
ioa[i]->total_len = 0;
ioa[i]->avl = NULL;
}
return ioa;
}
void insertName(IndexOfAuts * ioa, char *nome)
{
char *aux = malloc(sizeof(nome));
aux = trim(nome);
int index = getIndexOfLetter(aux);
if (nameLen(aux) > getSizeOfLongName(ioa[index]))
{
strcpy(ioa[index]->biggestn, aux);
ioa[index]->sizeof_biggestn = nameLen(aux);
}
ioa[index]->total_len += nameLen(aux);
insert(ioa[index]->avl, aux);
}
This is an important part of a module I need for a project, and on its main it's Seg Faulting. I suspect it's on the creation of an "object" newIndexOfAuts(),
The idea of this module is to have an array of 27 pointers to those structures, one to each letter and another to the special characters;
Now I'm just confused because it might be from the problem above or from a module loader I made:
void loadModules(char *filename, IndexOfAuts * ioa, StatTable st)
{
char *nameofile = malloc(20);
strcpy(nameofile, filename);
FILE *file = fopen(nameofile, "r");
if (file != NULL)
{
int counter, ano;
char *buff, *field, *auxil;
buff = malloc(1024);
field = malloc(200);
auxil = malloc(200);
while (fgets(buff, 1024, file))
{
counter = 0;
field = strtok(buff, ",");
printf("inserting 1st name\n");
insertName(ioa, field);
counter++;
while (!atoi(field))
{
if ((auxil = strtok(NULL, ",")) != NULL)
{
counter++;
field = auxil;
insertName(ioa, field);
}
}
ano = atoi(field);
incPub(st, ano, counter - 1);
}
fclose(file);
}
}
When i run this in main that has the following lines:
printf("Creating Stat Table");
StatTable st=newStatTable();\\This Line is correct, i checked it,i hope
printf("Creating index");
IndexOfAuts* ioa=newIndexOfAuts();
printf("Loading Modules");
loadModules(filename,ioa,st);
Those prints were for me to see where was the cause of the seg fault, but the last line printed was the "Creating Index".
There are several cases of undefined behavior and one memory leak (and a possible case of undefined behavior too):
You have this initialization ioa[i]->biggestn=""; It make the biggestn member point to a constant array of one character (the '\0' character). You then do strcpy(ioa[index]->biggestn,aux); which will write over a constant character, and then go outside of the array writing into unknown memory.
You have this: char* aux=malloc(sizeof(nome)); That allocates only 4 or 8 bytes, which the size of the pointer and not what the pointer points to. Use strlen to get the length of a string.
For the above allocation you also need to allocate a byte extra, as strlen only returns the length of the string without the terminator.
You have aux=trim(nome); This overwrites the pointer you just allocated, leading to a memory leak.
The above call might also lead to undefined behavior if you return a pointer to a local variable or array.
There are probably other problematic lines, these were just the ones I found on a quick glance.
And a general tip: Learn to use a debugger! The debugger is a programmers best tool next to the compiler. If you run your program in a debugger, the debugger will stop at the location of the crash, and let you examine (and also walk up) the function call stack, as well as let you examine values of variables.

C program pointers crashing system calls

// Struct for Country Data
typedef struct
{
char name[50]; // Country name
char code[3]; // Country code
int population; // Country Population
double lifeExp; // Country Life expectancy
} CountryData;
// Struct for Dir File
typedef struct
{
char code[3];
int offSet;
} DirData;
// Function Declarations
void fillCountryStructs(CountryData ** dataPtr, int nLines, int fd);
void fillDirectoryStructs(CountryData **dataPtr, DirData **director, int nLines,int fd2);
void sortStructs(DirData **director, int nLines);
int verifyString(char *s1, char *s2);
// Main Function
// - This function starts the program, get the number of lines as a
// parameter, fills the structs and writes the data to the Country
// File and the Directory file.
int main(int argc, char *argv[]) // Always remember to pass an argument while executing
{
// Some variables
int nLines; // The number of lines
char *pEnd; // For String functions
FILE *Fin,*Fout; // File pointers
int fd;
int fd2;
nLines = strtod(argv[1], &pEnd);
CountryData **countryDataPtr; // Array of structs
CountryData **tempStruct;
DirData **director;
// Allocate memory for the struct pointers
countryDataPtr = calloc(nLines, sizeof(CountryData*));
director = calloc(nLines, sizeof(DirData*));
// File Stream for "AllCountries.dat"
if((fd = open("AllCountries.dat", O_RDWR)) ==-1)
err_sys("File not found...\n");
// File Stream for "RandomStruct.bin"
if ((fd2 = open("RandomStruct.bin", O_RDWR)) == -1)
err_sys("Failed to open binary\n");
// Filling the Country stucts
fillCountryStructs(countryDataPtr, nLines, fd);
close (fd);
//fclose(Fin); // Closing the file "AllCountries.dat"
// Writing Binary File
write(fd2, (countryDataPtr[0]->name[0]), sizeof(CountryData));
close (fd2);
//fclose(Fout);
printf("RandomStruct.bin written Sucessfully\n");
// Filling the Directory File
// File Stream for "RandomStructDir.dir"
if ((fd2 = open("RandomStructDir.dir",O_RDWR|O_TRUNC)) != -1)
err_sys("Failed to open binary\n");
fillDirectoryStructs(countryDataPtr, director, nLines, fd2);
sortStructs(director, nLines); // Sorting the structs
// Write the number of lines in the FIRST LINE
// of the Directory File
write(fd2, nLines, sizeof(nLines));
// Writing Directory File after the number of lines was written
write(fd2,(director[0]->code[0]), sizeof(DirData));
close (fd2);
//fclose(Fout);
printf("RandomStructDir.dir written Sucessfully\n\n");
exit(0);
}
// Filling the Country structs
// - This function extracts the data from the file using strtok
// and fills all the structs with their corresponding values.
void fillCountryStructs(CountryData **dataPtr, int nLines, int fd)
{
int curLine = 0; // Current line
int index = 0; // The index
char buf[BUFSIZE]; // The Buffer with the size of BUFSIZE
char *tok; // Token
char *pEnd; // For the String functions
char ch = 'a'; // The temp character
int temPop;
double temLifeExp;
int num=0;
for(curLine = 0; curLine < nLines; curLine++)
{
// Reading each line
dataPtr[curLine] = (CountryData *)calloc(1, sizeof(CountryData));
index = 0;
do
{
read(fd, &ch, 1);
buf[index++] = ch;
}
while(ch != '\n');
// Strtoking...
tok = strtok(buf, ",\n");
index = 1;
while(tok != NULL)
{
tok = strtok(NULL, ",\n");
// Get the Country Code
if(index == 1)
{
strcpy(dataPtr[curLine]->code, tok); // Copying code to the struct
}
// Get the Country Name
if(index == 2)
{
strcpy(dataPtr[curLine]->name, tok); // Copying name to the struct
}
// Get the Country Population
if(index == 7)
{
temPop = (int)strtol(tok, &pEnd, 10);
dataPtr[curLine]->population = temPop; // Copying population to the struct
}
// Get the Country Life expectancy
if(index == 8)
{
num=countchar(tok);
printf ("The number of characters entered is %d\n", num);
printf ("The character entered is %s\n",tok);
temLifeExp = strtod(tok, &pEnd);
dataPtr[curLine]->lifeExp = temLifeExp; // Copying life expectancy to the struct
}
index++;
}
}
}
int countchar (char list[])
{
int i, count = 0;
for (i = 0; list[i] != '\0'; i++)
count++;
return (count);
}
// Filling the Directory Structs
// - This function fills the directory with the offset
void fillDirectoryStructs(CountryData **dataPtr, DirData **director, int nLines, int fd2)
{
int i = 0;
for(i = 0; i < nLines; i++)
{
strcpy(director[i]->code, dataPtr[i]->code); //It crashes in this Line
director[i]->offSet = sizeof(CountryData) * (i);
}
}
// Sorting the Dir Structs
// - This function sorts the Directory Structs.
void sortStructs(DirData **director, int nLines)
{
int maxNumber;
int i;
DirData **temp;
temp = calloc(1, sizeof(DirData));
// Sorting the array of pointers!
for(maxNumber = nLines - 1; maxNumber > 0; maxNumber--)
{
for(i = 0; i < maxNumber; i++)
{
if((verifyString(director[i]->code, director[i+1]->code)) == 1)
{
temp[0] = director[i];
director[i] = director[i+1];
director[i+1] = temp[0];
}
}
}
}
// Veryfying the strings
// - This function compares two strings and return a specific value
// accordingly.
int verifyString(char *s1, char *s2)
{
int i;
if(strcmp(s1,s2) == 0)
return(0); // They are equal
for(i = 0; s1[i] != 0; i++)
{
if(s1[i] > s2[i])
return(1); // s1 is greater
else if(s1[i] < s2[i])
return(2); // s2 is greater
}
return (2); // s2 is greater
}
So I get segmentation fault and I have no Idea why? maybe is something about the pointers. I specified where it crashes (void fillDirectoryStructs) that method the first line.
When I compile I get :
Countries.c: In function 'main':
Countries.c:68: warning: passing argument 2 of 'write' makes pointer from integer without a cast
Countries.c:84: warning: passing argument 2 of 'write' makes pointer from integer without a cast
Countries.c:86: warning: passing argument 2 of 'write' makes pointer from integer without a cast
Countries.c:232:2: warning: no newline at end of file
I don't know a lot about pointers but I have to use system calls, so I can't use any of the FILE * functions (fwrite(), etc) that is why I'm using plain write() and read().
When I run it I get segmentation fault when It gets to that point I just specified.
for test purposes I'm trying to print this
printf("test: %s\n", countryDataPtr[0]->code[0]);
instead of writing and it crashes there, why? what am I doing wrong? shouldn't that get the code of that first country in my struct? thanks
Well, you need to listen to your compiler and take its warnings seriously.
This:
write(fd2, nLines, sizeof(nLines));
is wrong, and would explain the warning. The variable nLines has type int, but if you look at the [documentation for write()] you can see that the 2nd argument has type void *.
So it will interpret your integer value as a pointer, and start reading memory which you have no right to be reading.
You need:
write(fd2, &nLines, sizeof nLines);
Note that sizeof is not a function, it only needs parenthesis when the argument is a type name (since it then needs a cast expression to the type in question, and casts are writen as a type name enclosed in parenthesis).
Also, you need to be prepared for the reality that I/O can fail. The write() function has a return value which you should be checking.
There are a number of other problems with your code, in addition to the serious one unwind pointed out.
This:
CountryData **countryDataPtr; // Array of structs
is not an Array of structs. Once allocated, it could be an array of pointers to structs.
This:
write(fd2, (countryDataPtr[0]->name[0]), sizeof(CountryData));
does not write one CountryData instance (much less a whole array of them). It takes the integer value of the first character of the first element's name, and treats it as a pointer just like you do with nLines.
If you want to write the first element, it would look like this:
write(fd2, countryDataPtr[0], sizeof(CountryData));
and if you wanted to write all the elements, you'd either need a loop, or a contiguous array of structs you can write in one go.

Resources