Get the variable value from a previous struct in arrays of structs - c

I have the following struct:
struct V {
int d;
int tip;
char naziv[10];
int veza;
int tezina;
};
typedef struct V Vertex;
The following declaration:
void kreiranje(Vertex cvorovi[]);
The following main function:
int main(){
int n=15;
Vertex cvorovi[n];
Vertex *pokazivac = &cvorovi[n];
kreiranje(pokazivac);
}
And this is the code behind the kreiranje function:
void kreiranje(Vertex cvorovi[])
{
int x,y,d,f,g;
int i = 0;
int brojac = 0;
char z[10];
char line[50];
char lined[50];
FILE *fr;
FILE *fp;
fr = fopen ("nodes.txt", "rt");
fp = fopen ("edges.txt", "rt");
while(fgets(line, 50, fr) != NULL)
{
sscanf (line, "%d|%d %s", &x, &y, &z);
cvorovi[n].d = x;
cvorovi[n].tip = y;
strcpy(cvorovi[n].naziv, z);
if(brojac < n){
fgets(lined, 50, fp) != NULL;
sscanf (lined, "%d-%d,%d", &d, &f, &g);
if (cvorovi[n-1].d == d){
printf ("\n Cvor prosli je %d\n", cvorovi[n-1].d);
printf ("\n %d \n", d);
cvorovi[n].veza = y;
cvorovi[n].tezina = g;
}
else {
cvorovi[n].veza = y;
cvorovi[n].tezina = g;
}
}
brojac++;
}
fclose(fr);
fclose(fp);
}
The files are like this:
edges.txt
1-2,4
1-3,5
nodes.txt
1|1 EL_01
2|2 TF_01
In the first line of nodes.txt, first number presents the ID, that is used in edges.txt. My problem is the following - how can I check and assign if the ID has more than one of the connections that are given in the edges.txt (just like the example shows)?
The file values read okay, however I am not sure how can I get the previous member's of the struct values to use with comparison.

My problem is the following - how can I check and assign if the ID has more than one of the connections that are given in the edges.txt (just like the example shows)?
There are several ways to represent a graph in programs. I think in your case the easiest would be Adjacency Matrix or Incidence Matrix:
int AdjacencyMatrix[n][n];
somewhere in main():
memset(AdjacencyMatrix, 0, sizeof(AdjacencyMatrix));
In your reader function (kreiranje):
fgets(lined, 50, fp) != NULL;
sscanf (lined, "%d-%d,%d", &d, &f, &g);
int From=d;
int To=f;
AdjacencyMatrix[From][To]=1
AdjacencyMatrix[To][From]=1; <<- Only if this is undirected graph
then,
if you want to check node's X connections, use this:
for(i=0;i<n;++i) {
if(AdjacencyMatrix[X][i]==1) {
printf("Node %d links to %d\n", X, i);
}
}

You appear to want something a bit more like this:
/* ... data type and function declarations ... */
#define MAX_VERTICES 15
int main() {
Vertex cvorovi[MAX_VERTICES];
int n;
/* arguments are a pointer to the array _start_, plus its size: */
/* the number of vertices actually read is returned */
n = kreiranje(cvorovi, MAX_VERTICES);
/* ... */
return 0;
}
and
int kreiranje(Vertex cvorovi[], int n) {
int brojac = 0;
/* ... other local variable declarations ... */
while ((brojac < n) && (fgets(line, 50, fr) != NULL)) {
/* ... loop body ... */
brojac++;
}
return brojac;
}
I suggest having function kreiranje() return the number of vertices actually read, as shown, because you will need to know that to do anything further with them.
As to checking for multiple connections attributed to the same ID, you keep track of what you've read so far, and you read until you've seen enough to be confident that reading more is unnecessary. I know that's very abstract, but the details depend on the assumptions you can make about the form and organization of your data, and on the data structures you use in your program. If you're asking about a general approach to your problem rather than about details of how to implement it, then your question is probably inappropriate for SO.

Related

Sorting structures from files

I recently got an assignment to sort members in a struct by last name and if they are the same to sort by first name. What i have so far only reads their name and age from the file but I am not properly grapsing how I would be able to sort it. So far I gathered the data from the file but im at a loss from there. I followed a code I saw but i didnt get a proper grasping of the process so i reverted back to step one.
struct Members{
int id;
char fname[50];
char lname[50];
int age;
}bio;
int main(){
int i=0;
FILE *fptr;
file = fopen("Members Bio.txt", "r");
while ( fscanf(file, "%d%s%s%d", &bio[i].id,bio[i].fname,bio[i].lname,&bio[i].age) != EOF)
{
printf("%d %s %s %d %d\n", bio[i].id,bio[i].fname, bio[i].lname, bio[i].age);
i++;
}
fclose(fptr);
}
Can anyone help me out on this one?
Code goes something like this for your case.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Members{
int id;
char fname[50];
char lname[50];
int age;
};
typedef int (*compare_func)(void*, void*);
int struct_cmp(void* s1, void* s2)
{
int l_result = strcmp(((struct Members*) s1)->lname, \
((struct Members*) s2)->lname);
if (l_result < 0)
return 1;
else if (l_result > 0)
return 0;
else
return (strcmp(((struct Members*) s1)->fname, \
((struct Members*) s2)->fname) < 0 ? 1 : 0);
}
void sort(void* arr,long ele_size,long start,long end,compare_func compare)
{
// Generic Recursive Quick Sort Algorithm
if (start < end)
{
/* Partitioning index */
void* x = arr+end*ele_size;
long i = (start - 1);
void* tmp=malloc(ele_size);
for (long j = start; j <= end - 1; j++)
{
if ((*compare)(arr+j*ele_size,x))
{
i++;
// Swap is done by copying memory areas
memcpy(tmp,arr+i*ele_size,ele_size);
memcpy(arr+i*ele_size,arr+j*ele_size,ele_size);
memcpy(arr+j*ele_size,tmp,ele_size);
}
}
memcpy(tmp,arr+(i+1)*ele_size,ele_size);
memcpy(arr+(i+1)*ele_size,arr+end*ele_size,ele_size);
memcpy(arr+end*ele_size,tmp,ele_size);
i= (i + 1);
sort(arr,ele_size,start, i - 1,compare);
sort(arr,ele_size,i + 1, end,compare);
}
}
int main()
{
FILE* fp;
int bio_max = 3;
struct Members bio[bio_max]; // Define bio to be large enough.
/* Open FILE and setup bio matrix */
/* For testing */
bio[0].id = 0;
strcpy(bio[0].fname, "");
strcpy(bio[0].lname, "Apple");
bio[0].age = 0;
bio[1].id = 1;
strcpy(bio[1].fname, "");
strcpy(bio[1].lname, "Cat");
bio[1].age = 1;
bio[2].id = 2;
strcpy(bio[2].fname, "");
strcpy(bio[2].lname, "Bat");
bio[2].age = 2;
/* Sort the structure */
sort(bio, sizeof(struct Members), 0, bio_max - 1, struct_cmp);
/* Print the sorted structure */
for (int i = 0; i < bio_max; i++) {
printf("%d %s %s %d\n", bio[i].id, bio[i].fname, \
bio[i].lname, bio[i].age);
}
}
Output
0 Apple 0
2 Bat 2
1 Cat 1
If the strings are not sorting in the way you want, you can redefine the struct_cmp function. Code is self explanatory, the base logic in the code is pass an array and swap elements using memcpy functions. You cant use simple assignment operator if you want to be generic, so that is why the element size is explicitly passed.
Edit
The code was not handling the condition, if lname are same. I missed it thanks for #4386427 for pointing this out.
I think you should define bio to be an array. And google sort algorithms please. Also recommend you google how to use libc function qsort.

How to get struct from a file in C

I am new to programming and would like some help in for File in C.
This is my code
#include <stdio.h>
#include <string.h>
void read_file();
void write_fil();
void add();
void display();
void search();
#define NAME_CHRS 30
struct employee_rec
{ char name[NAME_CHRS];
int dependents;
float pay_rate;
};
struct employee_rec employee;
struct employee_rec emp_array[];
FILE *employ;
int count=-1;
void read_file(void)
{
int idx;
employ = fopen("EMPLOYEE.DAT", "a+");//i add
//for (idx=0; idx <= count; idx++)
fread(&emp_array[idx], sizeof emp_array[idx], 1, employ);
fclose(employ);
}
void write_file()
{
int x;
employ = fopen("EMPLOYEE.DAT", "a+");
for (x=0; x <= count; x++)
fwrite(&emp_array[x], sizeof emp_array[x], 1, employ);
fclose(employ);
}
void add()
{
count+=1;
printf("Enter name: ");
scanf("%s", emp_array[count].name);
printf("Pay rate, other dependents: ");
scanf("%f %i", &emp_array[count].pay_rate, &emp_array[count].dependents);
}
void display()
{
int idx;
read_file();
printf("Name\t\tPay Rate\tDependents\n");
printf("----\t\t--------\t----------\n");
for (idx=0; idx <= count; idx++)
{
printf("%-10s\t%-8g\t%-8d\n", emp_array[idx].name, emp_array[idx].pay_rate, emp_array[idx].dependents);
}
}
void search()
{
char target[20];
int idx, found=0;
printf("Enter a name to search: ");
scanf("%s", target);
for (idx=0; idx <= count; idx++){
if(strcmp(emp_array[idx].name, target) == 0)
{
found = 1;
break;
}
}
if(found == 1)
{
printf("Name: %s\n", emp_array[idx].name);
printf("Pay rate: %g\n", emp_array[idx].pay_rate);
printf("Dependents: %d\n", emp_array[idx].dependents);
}
else
printf("Not found!\n");
}
int main(void)
{
int i;
//for (i=0; i < 3; i++)
// add();
// write_file();
display();
search();
return 0;
}
The original program would ask the user to key in data and then display it for the user.
So when another user runs the program and has the file it doesnt need to add more data but just read from the file
I have commented the for loop, display and search in my main because i just want to retrieve the data from my file.
Im not sure what to do with
fread(&emp_array[idx], sizeof emp_array[idx], 1, employ);
fclose(employ);
Since right now im using the counter from the insert to get the size, it will say size is 0 as the current run did not enter the data into the file (file already has data).
Is there any other way I can get all my data from the file without inserting it in the same run?
EDIT: So as some of the comments have mentioned the size of emp_arry is empty. I would like to get the size from a file. Since the file as a array inside which i want to transfer the data to emp_array.
One simple solution is to design a file header which includes the number of data in this file. Then, you can first read file header to get the number and then dynamically allocate memory to read data from file.

How to read dataset from text file to a 2D matrix

I have a dataset of form
0.547,0.797,2.860,1.398,Sharp-Right-Turn
0.541,0.786,2.373,1.919,Sharp-Right-Turn
0.549,0.784,2.370,1.930,Sharp-Right-Turn
0.983,0.780,2.373,1.701,Move-Forward
0.984,0.780,2.372,1.700,Move-Forward
0.983,0.780,2.378,1.602,Move-Forward
0.983,0.780,2.381,1.701,Move-Forward
.
.
ROWS=5456, COL 5
Its easy in MATLAB to load the text file into a data matrix. But am struggling in C.
I tried this code
int main()
{
struct node {
float at1;
float at2;
float at3;
float at4;
char at5[30];
} record[ROW][COL];
FILE *file;
int i, j;
memset(record, 0, sizeof(record));
file = fopen("sensor.txt", "r");
if (file == NULL) {
printf("File does not exist!");
} else {
for (i = 0; i < ROW; ++i) {
for (j = 0; j < COL; ++j) {
fscanf(file, "%f,%f,%f,%f,%s", &record[i][j].at1, &record[i][j].at2, &record[i][j].at3, &record[i][j].at4, &record[i][j].at5);
}
}
}
fclose(file);
for (i = 0; i < ROW; ++i)
for (j = 0; j < COL; ++j) {
printf("%f\t%f\t%f\t%f\t%s\n", record[i][j].at1, record[i][j].at2, record[i][j].at3, record[i][j].at4, record[i][j].at5);
}
return 0;
}
I am getting infinite rows and 4 cols of 0.000000 only.
I want to save the first four columns in one matrix and last column as another column matrix. Could I do that?
I have to build a classifier which I easily did in MATLAB without using predefined functions but reading data in C is hampering my code.
I know this might be a repeated question, but I tried solutions in other threads, they are not working on my dataset.
First of all you have defined a record holding all your fields, that together forms each row. This means that when you read you have all values for a row so the struct dimension should be the maximum record available that is a monodimensional array of structures record.
But you cannot allocate such an huge struct on the stack, it will overflow, it's better to allocate it in dynamic memory:
struct node {
float at1;
float at2;
float at3;
float at4;
char at5[30];
} record;
struct node *record = malloc(sizeof(struct node) * MAXRECORDS);
Another error is in the scanf, the last field of the structure record is already a pointer to char, so you don't need to dereference it.
This is a working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXRECORDS 10
int main(int argc, char *argv[])
{
struct node {
float at1;
float at2;
float at3;
float at4;
char at5[30];
};
struct node *record = malloc(sizeof(struct node) * MAXRECORDS);
FILE *file;
int nRecords = 0;
memset(record, 0, sizeof(record));
file = fopen("sensor.txt", "r");
if (file == NULL)
{
printf("File does not exist!");
}
else
{
while (EOF != fscanf(file, "%f,%f,%f,%f,%s", &record[nRecords].at1, &record[nRecords].at2,
&record[nRecords].at3, &record[nRecords].at4, record[nRecords].at5) && nRecords<MAXRECORDS)
{
nRecords++;
}
}
fclose(file);
for (int i = 0; i < nRecords; ++i)
{
printf("%f\t%f\t%f\t%f\t%s\n",
record[i].at1, record[i].at2,
record[i].at3, record[i].at4, record[i].at5);
}
return 0;
}
In a 'real' application you want dimension the array to some large enough value, and when you reach the end of the allocated space you can reallocate it for other data. This allows you to read a file of how many entries you want without knowing their number before the reading.
P.S. I added the check for maximum number of record to read. But this remain a sample, many checks are still missing i.e. I don't check value returned by malloc.

Reading a text file with data into a linked list

I am working on a project where I have to read the .txt file where I have data of four elements for each component, ex:
5 2 7 0.99 (which are the components id, inside node, outside node and reliability)
7 3 5 0.95
...
I want to read and write data into a linked list, over which I will later on be able to search for values and sign them to a new linked list. It's about a method of minimal paths in mechanical engineering used for calculating reliability of systems.
To test the code I just want to print out all the components that were put into the linked list. I get the right value for number of lines, but for components I just get out one random not all of them. Any kind of help will be much appreciated :)
Here is the code:
#include <stdlib.h>
#include <stdio.h>
struct Components_element {
int id;
int in_node;
int out_node;
float reliability;
struct Components_element *next_c;
};
struct Components_element *head_c = NULL;
int count_lines(char *filename)
{
int counter = 0;
char c;
FILE *ptr_sistem;
ptr_sistem = fopen(filename, "r");
if(ptr_sistem == NULL)
return 0;
while((c = fgetc(ptr_sistem)) != EOF)
if(c == '\n')
counter++;
fclose(ptr_sistem);
if(c != '\n')
counter++;
return counter;
}
struct Components_element *add_comp(struct Components_element *head_c, int id, int in_node, int out_node, float reliability)
{
struct Components_element *new;
struct Components_element *tail_c;
new = (struct Components_element*) malloc(sizeof(struct Components_element));
new->id = id;
new->in_node = in_node;
new->out_node = out_node;
new->reliability = reliability;
if(head_c == NULL)
return(new);
tail_c = head_c;
while(tail_c->next_c != NULL)
tail_c = tail_c->next_c;
tail_c->next_c = new;
return(head_c);
}
void write_out(struct Components_element *p)
{
while(p != NULL) {
printf("%d %d %d %f", p->id, p->in_node, p->out_node, p->reliability);
p = p->next_c;
}
printf("\n");
}
struct Components_element *empty(struct Components_element *p)
{
struct Components_element *tail_c;
while(p != NULL) {
tail_c = p;
p = p->next_c;
free(tail_c);
}
return(p);
}
main()
{
int i, id, in_node, out_node;
int n_lines;
float reliability;
struct Components_element *components;
FILE *ptr_file;
ptr_file = fopen("system.txt", "r");
if(ptr_file == NULL) {
printf("Cannot open file.\n");
return 0;
} else {
n_lines = count_lines("system.txt");
for(i = 0; i < n_lines; i++) {
fscanf(ptr_file, "%d %d %d %f", &id, &in_node, &out_node, &reliability);
components = add_comp(head_c, id, in_node, out_node, reliability);
++i;
}
}
printf("Number of lines: %d.\n", n_lines);
write_out(components);
empty(components);
fclose(ptr_file);
}
Writing the code is only a small fraction of what programming is about. The really hard part, is getting it to work as required.
To do this, we use various tools to aid with testing the code to make sure it works the way the programmer intended.
The most useful tool is the debugger. Learn how to use one and you can find your problem in a couple of minutes.
Sometimes, however, debuggers aren't always available and this is where things can get quite tricky and requires logging information (printf / fwrite / etc) and a lot of deductive reasoning.
But here, running the code through a debugger will show you your problem. I'll leave it as an exercise for you as you'd learn a lot more that way rather than having the answer spoon fed to you.

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