So for this project, we are required to check if words are palindromes by looking down a stack and forwards through a queue. I have all the logic together, as well as the #include in my palindrome.c file. All I'm having trouble with is defining it correctly while using (allocPQueue seen below) in my palindrome checking method.
Here is an excerpt the .c for PriorityQueue
#include "PriorityQueue.h"
PQueue* allocPQueue(uint elementSize, PQMode mode){
PQueue* pq = (PQueue*)calloc(1, sizeof(PQueue));
pq->elements = allocDList(elementSize, NULL, NULL);
//the elementSampling is to speed up search time, but it is not yet ready
//in order for it to work I cannot make a copy of DNode*, rather I should
//place the pointer of a DNode directly into the array
//I will call this a DeepDArray
pq->elementSampling = (GenericArray)allocDArray(10, sizeof(DNode*));
pq->mode = mode;
if(mode == PQMODE_STACK){
pq->priorityExtractor = &stackPriority;
}
else if(mode == PQMODE_QUEUE){
pq->priorityExtractor = &queuePriority;
}
return pq;
}
void releasePQueue(PQueue* pq){
if(pq){
if(pq->elements){
releaseDList(pq->elements);
}
if(pq->elementSampling){
releaseDArray(pq->elementSampling);
}
free(pq);
}
}
Object peekMin(PQueue* pq){
if(isEmptyPQueue(pq)){
return NULL;
}
Object data = malloc(pq->elements->elementSize);
memcpy(data, pq->elements->head->data, pq->elements->elementSize);
return data;
}
Here is the code in my palindrome.c file (excluding inclusions):
#include "PriorityQueue.h"
bool isPalindrome(char* str, uint length);
char getPalindromeChar(char c);
PQueue* stack;
PQueue* queue;
int main(int argc, char** argv){
if(isPalindrome(argv[1], strlen(argv[1]))){
printf("%s is a palindrome\n", argv[1]);
}
else{
printf("%s is not a palindrome\n", argv[1]);
}
return 0;
}
bool isPalindrome(char* str, uint length){
//TODO
//insert your check, you are only allowed to use a Stack, a Queue, and the char
//getPalindromeChar(char) helper function
char ch;
int wordLength;
int counter;
char stackChar;
char queueChar;
bool stillPalli;
stack = allocPQueue(sizeof(char), PQMODE_STACK); <--"undefined reference to 'allocPQueue'"
queue = allocPQueue(sizeof(char), PQMODE_QUEUE); <--"undefined reference to 'allocPQueue'"
wordLength = 0;
int i;
for(i = 0; i < length; i++){ // Goes through the str array, looking char-by-char for
ch = str[i];
ch = getPalindromeChar(ch);
wordLength++;
// places them in stack and queue
add(stack,ch);
add(queue,ch);
}
stillPalli = true;
while(stillPalli && (counter < wordLength)){
stackChar = top(stack);
pop(stack);
queueChar = front(queue);
dequeue(queue);
// test for equality
if(strcmp(stackChar, queueChar) != 0){
stillPalli = false;
}
counter++;
}
}
Declare your function allocPQueue() inside PriorityQueue.h:
extern PQueue* allocPQueue(uint elementSize, PQMode mode);
When compiling your palindrome.c the compiler needs to know that there is, somewhere, a function that will be available at link time.
The extern keyword does exactly this: it populates the compiler symbol table but don't try to define the actual contents (the assembly code, in the case of a function) of it. The compiler will output the object code (palindrome.o) with annotations that this function still lacks a definition. It will come from another object file.
Then enters the linker. You should pass both palindrome.o and PriorityQueue.o, so that no reference goes undefined on the final executable file.
Related
I've just begun learning the C language and I ran into an issue with one of my programs.
I am getting an error: "Illegal instruction 4" when executing: ./dictionary large.txt
Large.txt is a file with 143091 alphabetically sorted words, with each word starting on a new line. I am trying to load all of them into a hash table and return true if all the words are loaded successfully.
This code works for me if the code in bool load() is within int main and load() is non-existent. However, once I place it inside the load() function and call it from main, I get an error.
I would appreciate help on this, as there are not many threads on Illegal instruction.
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
// Maximum length for a word
// (e.g., pneumonoultramicroscopicsilicovolcanoconiosis)
#define LENGTH 45
// Number of letters in the english alphabet
#define ALPHABET_LENGTH 26
// Default dictionary
#define DICTIONARY "large.txt"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
} node;
// Number of buckets in hash table
const unsigned int N = ALPHABET_LENGTH;
// Hash table
node *table[N];
// Load function
bool load(char *dictionary);
// Hash function
int hash(char *word);
int main(int argc, char *argv[])
{
// Check for correct number of args
if (argc != 2 && argc != 3)
{
printf("Usage: ./speller [DICTIONARY] text\n");
exit(1);
}
// Determine which dictionary to use
char *dictionary = (argc == 3) ? argv[1] : DICTIONARY;
bool loaded = load(dictionary);
// TODO: free hashtable from memory
return 0;
}
bool load(char *dictionary)
{
// Open dictionary for reading
FILE *file = fopen(dictionary, "r");
if (file == NULL)
{
printf("Error 2: could not open %s. Please call customer service.\n", dictionary);
exit(2);
}
// Initialize array to NULL
for (int i = 0; i < N; i++)
table[i] = NULL;
// Declare and initialize variables
unsigned int char_count = 0;
unsigned int word_count = 0;
char char_buffer;
char word_buffer[LENGTH + 1];
int hash_code = 0;
int previous_hash_code = 0;
// Declare pointers
struct node *first_item;
struct node *current_item;
struct node *new_item;
// Is true the first time the while loop is ran to be able to distinguish between hash_code and previous_hash_code after one loop
bool first_loop = true;
// Count the number of words in dictionary
while (fread(&char_buffer, sizeof(char), 1, file))
{
// Builds the word_buffer by scanning characters
if (char_buffer != '\n')
{
word_buffer[char_count] = char_buffer;
char_count++;
}
else
{
// Increases word count each time char_buffer == '\n'
word_count += 1;
// Calls the hash function and stores its value in hash_code
hash_code = hash(&word_buffer[0]);
// Creates and initializes first node in a given table index
if (hash_code != previous_hash_code || first_loop == true)
{
first_item = table[hash_code] = (struct node *)malloc(sizeof(node));
if (first_item == NULL)
{
printf("Error 3: memory not allocated. Please call customer service.\n");
return false;
}
current_item = first_item;
strcpy(current_item->word, word_buffer);
current_item->next = NULL;
}
else
{
new_item = current_item->next = (struct node *)malloc(sizeof(node));
if (new_item == NULL)
{
printf("Error 4: memory not allocated. Please call customer service.\n");
return false;
}
current_item = new_item;
strcpy(current_item->word, word_buffer);
current_item->next = NULL;
}
// Fills word buffer elements with '\0'
for (int i = 0; i < char_count; i++)
{
word_buffer[i] = '\0';
}
// Signals the first loop has finished.
first_loop = false;
// Clears character buffer to keep track of next word
char_count = 0;
// Keeps track if a new table index should be initialized
previous_hash_code = hash_code;
}
}
return true;
}
// Hash in order of: 'a' is 0 and 'z' is 25
int hash(char *word_buffer)
{
int hash = word_buffer[0] - 97;
return hash;
}
Thank you in advance!
Chris
You should use node *table[ALPHABET_LENGTH]; for the table declaration instead of node *table[N];
There is a difference between constant macros and const variables, a macro can be used in a constant expression, such as a global array bound as per your use case, whereas a const variable cannot.
As you can see here, the compiler you say you are using, gcc, with no compiler flags, issues an error message:
error: variably modified 'table' at file scope
You can read more about these differences and use cases in "static const" vs "#define" vs "enum" it has more subjects, like static and enum, but is a nice read to grasp the differences between these concepts.
Here I am trying to implement a stack, where only opening braces from a string will be filtered out and stored in an array. The code I wrote stored the values in stackArr array. But whenever I attempt to print out the array, my code fails. It doesn't give any specific error message, it just fails to execute.
I think problem is in the following portion:
i = 0;
while(stackArr[i] != '\0')
{
printf("%c ",stackArr[i]);
i++;
}
Full code :
#include<stdio.h>
#include<stdlib.h>
int main()
{
char braces[10];
char stackArr[10];
int front = -1,rear = -1,size = 10;
gets(braces);
checkValidate(&braces,&stackArr,&front,&rear,size);
}
void checkValidate(char *braces,char *stackArr,int *front,int *rear,int size)
{
int i = 0;
while(braces[i] != '\0')
{
if((braces[i] == '(') || (braces[i] =='{') || (braces[i] =='['))
{
push(braces[i],&stackArr,&front,&rear,size);
}
i++;
}
//print(&front,&rear,size,*stackArr);
i = 0;
while(stackArr[i] != '\0')
{
printf("%c ",stackArr[i]);
i++;
}
}
void push (char val,char *stackArr,int *front,int *rear,int size)
{
if(isFull(*front,*rear,size))
{
printf("your string is larger that valid size\n");
}
else
{
if(isEmpty(*front,*rear))
{
*front = 0;
}
*rear = (*rear+1) % size;
stackArr[*rear] = val;
/*printf("%d ",*rear);
printf("%c",stackArr[*rear]);
printf("\n");*/
}
}
int isEmpty(int front,int rear)
{
if(front == -1 && rear == -1)
{
return 1;
}
else
{
return 0;
}
}
int isFull(int front,int rear,int size)
{
if(front == 0 && rear == size -1)
{
return 1;
}
else
{
return 0;
}
}
void print(int *front,int *rear,int size,char *arr)
{
int i;
for(i = *rear;i != *front; i = (i-1)% size)
{
printf("%c\n",arr[i]);
}
printf("%c\n",arr[i]);
}
Your code must produce a lot of warnings on compile, because the functions that you call lack forward declarations. Hence, compiler assumes that all functions that you call have parameters of type int, and that they also return an int. Since your functions take pointers instead, the calls of your functions result in undefined behavior, which is likely leading to a crash.
// Put these declarations in front of main
void checkValidate(char *braces,char *stackArr,int *front,int *rear,int size);
void push (char val,char *stackArr,int *front,int *rear,int size);
int isEmpty(int front,int rear);
int isFull(int front,int rear,int size);
void print(int *front,int *rear,int size,char *arr);
Adding forward declarations should fix this problem. In addition, you need to replace the now-deprecated gets call with a call to fgets, which is safe from buffer overruns.
You also pass pointers to arrays to functions that expect pointers to character. You need to remove & in front of braces and stackArr. Turn on compiler warnings to see all places where this needs to be done.
Finally, your code expects stackArr to be null-terminated, but you never set its elements to zeros. Add char stackArr[10] = {0} to initialize the array to zeros.
I have the following problem.
I need to create a list of savestates with dynamical length. That's why I decided to create a list by defining some structs and connecting dynamically created structs together to build a list of structs which can dynamically be extended and so on.
However, some things seem to not work at all. Here's the relevant code first:
saves.h:
#ifndef SAVES_H
#include<time.h>
#define SAVES_H
#define SVS_STRLEN 500
#define SVS_FILE "savefile.dat"
#define True 1
#define False 0
typedef struct SVS_STATE SVS_STATE;
typedef struct SVS_STATES SVS_STATES;
struct SVS_STATE {
int i_playfield[6][7];
int i_turn;
time_t i_time;
void *next;
};
struct SVS_STATES {
SVS_STATE *states;
int count;
int loaded;
};
void SVS_Add_State(int i_playfield[][7], int i_turn, time_t i_time);
void SVS_Debug_State(SVS_STATE *state);
void SVS_Format_State(SVS_STATE *state, char text[]);
SVS_STATE *SVS_Get_State(int number);
#endif
saves.c:
#include "saves.h"
#include<string.h>
#include<time.h>
SVS_STATE *SVS_Get_State(int number)
{
int i = 1;
SVS_STATE *state;
if (svs_current_state.loaded == False) return NULL;
if (number > svs_current_state.count) return NULL;
state = svs_current_state.states;
printf("printing state 1:");
SVS_Debug_State(state);
while( i < number)
{
i++;
state = (SVS_STATE*)(state->next);
printf("printing state %i:", i);
SVS_Debug_State(state);
}
return state;
}
void SVS_Format_State(SVS_STATE *state, char text[])
{
int i, j;
if (svs_current_state.loaded == False) return;
text[0] = '\0';
strcat(text, "{\0");
for (i = 0; i < X_SIZE; i++)
{
strcat(text, "{\0");
for(j = 0; j < Y_SIZE; j++)
{
strcat(text, "%i,\0");
sprintf(text, text, state->i_playfield[i][j]);
}
strcat(text, "}\0");
}
strcat(text, "};%i;%i\n\0");
sprintf(text, text, state->i_turn, state->i_time);
printf("\nFormatted state:%s\n", text);
}
void SVS_Debug_State(SVS_STATE *state)
{
char text[SVS_STRLEN];
SVS_Format_State(state, text);
printf("%s\n", text);
}
void SVS_Add_State(int i_playfield[][7], int i_turn, time_t i_time)
{
int i, j;
SVS_STATE *laststate, *newstate;
newstate = (SVS_STATE*)malloc(sizeof(SVS_STATE));
printf("adding state with time:%i\n", i_time);
if (svs_current_state.loaded == False) return;
for (i = 0; i < 6; i++)
for (j = 0; j < 7; j++)
newstate->i_playfield[i][j] = i_playfield[i][j];
newstate->i_turn = i_turn;
newstate->i_time = i_time;
newstate->next = NULL;
printf("initialized state:");
SVS_Debug_State(newstate);
if (svs_current_state.coun > 0)
{
laststate = SVS_Get_State(svs_current_state.count);
laststate->next = (void*)newstate;
} else
svs_current_state.states=newstate;
svs_current_state.count++;
}
int main()
{
int i_playfield[6][7] = {0};
// mark saves library as loaded here, but removed function, since it
// just sets svs_current_state.loaded (which is the global struct of
// type SVS_STATES) to 1
SVS_Add_State(i_playfield, 1, time(NULL));
i_playfield[0][0] = 2;
SVS_Add_State(i_playfield, 2, time(NULL));
return 0;
}
The actual problems I encountered while using the printf's and Debug_State calls in these functions:
- the i_time I give is printed out once in Add_State(), correctly. Means it is a legal time and stuff, but when printed out after creating the full state by using Format_State() the string is 50 percent to long and the last part is displayed twice, for example:
if the time is 12345678, it is displayed correctly while debugging in Add_State, but Format_State() displays 123456785678.
- second problem: the first state added works, more or less, fine. But after adding a second one, printing the first state (retrieved by using Get_State and formatted with Format_State) prints a mixture of two states, for example something like this:
state 1: {{0,0,0,0,0,0,0}{0,0,0,0,0,0,0}{0,0,0,0,0,0,0}...
{0,0,0,0,0,0}};1;123456785678
state 2: {{0,0,0,0,0,0}{0,0,0,0,0,0}...
{0,0,0,0,0,0}};2;1234567856785678,0}{0,0,0,0,0,0}...
Thanks for reading.
These calls
sprintf(text, text, ...
invoke undefined behaviour, as the target buffer and one of the other arguments overlap.
From the POSIX specs to sprintf():
If copying takes place between objects that overlap as a result of a call to sprintf() [...], the results are undefined.
I'm new to C / pointers / memory management and am having trouble implementing a few functions for a project I'm working on.
In my builtins.c file, I have a function called printalias that is called to print all the alias names and corresponding values stored in my program. At the end, I want to print one of the alias names by retrieving it via another function called getal.
int x_printalias(int nargs, char *args[]) {
int i = 0;
// Loop through, print names and values
for(i = 0; i< 100; i++)
{
if(alias_names[i][0]!='\0' && !alias_disabled[i])
{
char * var = alias_names[i];
char * val = alias_vals[i];
fprintf(stderr,"%s = %s\n", var, val );
}
}
// This is where I want to retrieve the string from another function
char * hello = "brett";
hello = getal(hello);
fprintf(stderr,"Got alias for brett --> %s",hello);
return 0;
}
My getal function exists in my shellParser.c file and looks like this, generally performing the same looping and returning when it is found:
const char * getal(int nargs, char *args[])
{
fprintf(stderr,"\nRetrieving alias...\n");
int i = 0;
fprintf(stderr, "check1\n" );
fprintf(stderr,"Got args[0]: %s\n", args[0]);
while (alias_names[i][0]!='\0' && i < MAX_ALIAS_LENGTH ) // Find empty slot in variables array
{
fprintf(stderr, "check2\n" );
fprintf(stderr,"I is currently %i and current varible in slot is %s\n",i,alias_names[i]);
//strncpy(hello, variables[i], MAX_VAR_LENGTH); // Variable at current slot
if(strcmp(alias_names[i], args[0]) == 0) // If we have an entry, need to overwrite it
{
fprintf(stderr,"Found alias %s = %s at spot %i\n",args[0],alias_vals[i], i); // Not at end if here
return alias_vals[i];
}
i++;
}
fprintf(stderr, "check3\n" );
// Elided....
return '\0';
}
In the end of my printalias function, I want to test that this getal function is working by calling it on a hardcoded string "brett". However, when I call my printalias function from the command line, it makes it to the "Check 1" print statement and then simply quits without error or return value.
I think this has something to do with my memory management or incorrect declaration of variables with pointers. Can anybody spot something (or a lot of things) that I'm doing wrong here?
You must declarete list of argument for to call getal and it call with these
list.
And pointer of return values getal must be const char*
//....
// This is where I want to retrieve the string from another function
char * hello[] = {"brett"}; // this list argument for getal function
const char *strGetal;
strGetal = getal(1,hello);
fprintf(stderr,"Got alias for brett --> %s",strGetal);
return 0;
}
Example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char** get_all(int argc, char **argv)
{
char *value;
char **values = NULL;
int i;
values = (char**) malloc(sizeof (char) * argc);
if (values == NULL) {
perror("malloc");
return NULL;
}
for (i = 0; i < argc; i++, argv++) {
value = strchr(*argv, ':');
values[i] = (value + 1);
}
return values;
}
int main()
{
char *args[] = {"key:a", "key:b", "key:c"};
char **values;
int i;
values = get_all(3, args);
for (i = 0; i < 3; i++) {
puts(values[i]);
}
return 0;
}
// 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.