Link to home
Start Free TrialLog in
Avatar of crazy4s
crazy4s

asked on

Sorting an array of structs

Hi all,
I was having problem in sorting the array. Currently I'm trying to build the index array in memory, sort it(using insertion sort and sort according to the country code) and then write the whole sorted array(country code with offset) into a file.

This is what I have so far:
#include	<stdio.h>
#include 	<string.h>
#include 	<stdlib.h>
#include 	"ourhdr.h"

typedef struct				// Country Data struct declaration
    	{  	
		char code[4]; 		// Country Code 
       		char name[50];		// Country Name
		float life_expectancy;	// Life Expentancy of the Country's citizen
		int pop;		// Country's Population
    	} DATATYPE;

typedef struct				// Index Data struct declaration
	{
		char code[4];		
		long int offset;	// offset of the data
	} INDEX;

INDEX StructArray[300];
DATATYPE ActualStruct; // for a single struct

void sort(INDEX SortArray[], int n)
{
	int k, j;
	char **temp;
	for (k=2;k<n;k++)
	{
		temp = SortArray[k].code;
		for (j=k-1;j>=0; j++)
		{
			if(strcmp(SortArray[j].code, temp) > 0)
			{
			SortArray[j+1].code = SortArray[j].code;
			}
		}
		SortArray[j+1].code = temp;
	}
}

int main() 
{ 

	//int m, size;
	int i = 0;
	int size=0;
	FILE *FI, *FO, *FO2;
	char Line[1000];  // NO input line (delimited by \n) is longer than 1000

	char * Tok;         // token from line
	if((FI = fopen("AllCountries1.txt", "r")) == NULL) // open a stream from "countries"
    		err_sys("Open Fail\n");

	if((FO = fopen("DATABASE.txt", "wb")) == NULL) // open a stream from "countries"
    		err_sys("Open DATABASE Fail\n");

	if((FO2 = fopen("DIRECTORY.txt", "w+")) == NULL) // open a stream from "countries"
    		err_sys("Open DIRECTORY Fail\n");

    while ( fgets( (char *) Line,1000,FI) != NULL) // fill buffer up to newline or eof or error
    {

	Tok = strtok( Line ,",\n"); 	// skip ID number

        Tok = strtok( NULL ,",\n"); 	// this should get the country code 
        ActualStruct.code[0] = Tok[0];
        ActualStruct.code[1] = Tok[1];
        ActualStruct.code[2] = Tok[2];
        ActualStruct.code[3] = 0; 	// To create "string" 

	Tok = strtok( NULL ,",\n"); 	// this should get the country name 
        strncpy(&ActualStruct.name[0],Tok,50);	// copy string at most 50 chars

	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 
	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 

	Tok = strtok( NULL ,",\n"); 	// this should get the population
	ActualStruct.pop = atoi(Tok);	// convert string to integer

        Tok = strtok( NULL ,",\n"); 	// this one should get life expectancy
        ActualStruct.life_expectancy = atof(Tok);	// convert string to a floating point number

	strcpy(StructArray[i].code, ActualStruct.code);                  // get the current code 
	StructArray[i].offset = ftell(FO);                               // get the current offset in the DATABASE file 

	if (fwrite(&ActualStruct, sizeof(DATATYPE),1,FO) != 1)  // write the struct to the DATABASE file 
		err_sys("fwrite error");

	printf("%5s%50s%15u%18f%10u\n",&ActualStruct.code[0],&ActualStruct.name[0],ActualStruct.pop,ActualStruct.life_expectancy,StructArray[i].offset);
	
	i++;
	}
	
	printf("Before Sort:\n");
	for (i=0; i<size; i++)
	{
		printf("%s \t %u\n",StructArray[i].code, StructArray[i].offset);
	}	
	sort(StructArray,size);
	printf("After Sort:\n");
	for (i=0; i<size; i++)
	{	
	printf("%s \t %u\n",StructArray[i].code, StructArray[i].offset);
	}
	
	if (fclose(FI))				// close file descriptor FI
		err_sys("Close error\n");	
	if (fclose(FO))				// close file descriptor FO
		err_sys("Close error\n");	
	if (fclose(FO2))			// close file descriptor FO2
		err_sys("Close error\n");

    	printf(" Made the break \n");  // and this if not error :) 

}

Open in new window


however I'm getting these error:
test1.c: In function `sort':
test1.c:88: warning: assignment from incompatible pointer type
test1.c:91: warning: passing arg 2 of `strcmp' from incompatible pointer type
test1.c:93: error: incompatible types in assignment
test1.c:96: error: incompatible types in assignment

Thanks in advance.
ASKER CERTIFIED SOLUTION
Avatar of phoffric
phoffric

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of crazy4s
crazy4s

ASKER

i complied with no errors but when i try to print out the sorted array nothing is printed out?
--------------------------------------------------------------------------------------------------------
  CODE                   COUNTRY NAME                      POPULATION      LIFE EXPECTANCY    OFFSET
--------------------------------------------------------------------------------------------------------
  DZA                                           Algeria       31471000         69.699997         0
  AGO                                            Angola       12878000         38.299999        64
  BEN                                             Benin        6097000         50.200001       128
  BWA                                          Botswana        1622000         39.299999       192
  9344
Before Sort:
After Sort:
 Made the break


Avatar of crazy4s

ASKER

I've figured out that i defined int size =0; that's why it prints out nothing.
however when i change it to int size; it only outputs the following?

--------------------------------------------------------------------------------------------------------
  CODE                   COUNTRY NAME                      POPULATION      LIFE EXPECTANCY    OFFSET
--------------------------------------------------------------------------------------------------------
  DZA                                           Algeria       31471000         69.699997         0
  AGO                                            Angola       12878000         38.299999        64
  BEN                                             Benin        6097000         50.200001       128
  BWA                                          Botswana        1622000         39.299999       192
.
.
.
Before Sort:
DZA      0
AGO      64
BEN      128
BWA      192
IOT      256
BFA      320
BDI      384
CMR      448
Segmentation Fault (core dumped)
>> however when i change it to int size; it only outputs the following?
But now size is on the stack with only a garbage value. Then you use size without setting it in line 97 and 101. It looks like size is the count of lines in your input file, so adjust it as your read in the lines.

Be careful - if your input file has 2 lines, and size is then 2, then when you call sort(), n =2.
     for (k=2;k<n;k++)  
then this loop does not go into the body.

Avatar of crazy4s

ASKER

can you elaborate in more details? i'm not really understand.
thank you.
You are using size in various locations in your program. What should size be if there are, say, two lines in your input file?

Currently, when you use size, it has not been set to any value. In your OP code, you set it to 0, but then you found that lines 97 and 103 resulted in no printout. So, you must set size to a meaningful value before you use it.
Avatar of crazy4s

ASKER

can i set the size according to the structs something like sizeof(INDEX)?
What is your definition of size?
Avatar of crazy4s

ASKER

do u meant you want me to put like this?
#define size 300;
as before that i defined
INDEX StructArray[300];
You have this code,
INDEX StructArray[300];

Open in new window

So, that means that you have an array of 300 INDEX items.

If you now say that size is 300, then what do you think will happen in the following code if you didn't enter 300 values for StructArray?
        for (i=0; i<size; i++)  
        {  
                printf("%s \t %u\n",StructArray[i].code, StructArray[i].offset);  
        }

Open in new window

In the while loop before this code, you don't necessarily fill up 300 items in this array, right?
Avatar of crazy4s

ASKER

yea i tried it and it prints out 300 lines even though i don've that much and it prints out the rest as 0?
>> it prints out 300 lines even though i don've that much
Yes, it prints out 300 lines because the for loop says to print out 300 lines. Now, if you set the value of size to just the number of lines you really want to print out, then at least that part will be working better. So, just count the number of lines that you read in, and whatever that number is, that will be your size.
Avatar of crazy4s

ASKER

do u meant like let's say i've 147 lines so i should put something like tat?
for(i=0; i<147;i++)

but the sorted array still can't be printed out
and i got a segmentation fault for that
Where did the number 147 come from?

About all I can say given the code you have written is that you need to count the number of times that you loop through the while loop. At Line 91 you print out some information - the contents of a line in your input file. You need to figure out how many times line 91 is executed. That number is the number of lines in your input file. Remember this program has to work for different input files having different number of entries. The size has to be computed. It cannot be hard-coded.
Avatar of crazy4s

ASKER

hmm so do you meant that should put this inside my while loop
int size;
and at the end of while loop i'll put a size++;

or can you give some example that will be easier for me to understand?
thank you.
Avatar of crazy4s

ASKER

ok now this is the latest code i've now but it gives me a segmentation fault for sort
#include	<stdio.h>
#include 	<string.h>
#include 	<stdlib.h>
#include 	"ourhdr.h"


typedef struct				// Country Data struct declaration
    	{  	
		char code[4]; 		// Country Code 
       		char name[50];		// Country Name
		float life_expectancy;	// Life Expentancy of the Country's citizen
		int pop;		// Country's Population
    	} DATATYPE;

typedef struct				// Index Data struct declaration
	{
		char code[4];		
		long int offset;	// offset of the data
	} INDEX;

INDEX StructArray[300];
DATATYPE ActualStruct; // for a single struct

void sort(INDEX SortArray[], int n)
{
	int k, j;
	char *temp;
	for (k=1;k<n;k++)
	{
		temp = SortArray[k].code;
		for (j=k-1;j>=0; j++)
		{
			if(strcmp(SortArray[j].code, temp) > 0)
			{
				strcpy( SortArray[j+1].code, SortArray[j].code);
			}
		}
  		strcpy( SortArray[j+1].code,  temp); // strcpy
	}
}

int main() 
{ 
	int i = 0;
	int size;
	FILE *FI, *FO, *FO2;
	char Line[1000];  // NO input line (delimited by \n) is longer than 1000

	char * Tok;         // token from line
	if((FI = fopen("AC1.txt", "r")) == NULL) // open a stream from "countries"
    		err_sys("Open Fail\n");

	if((FO = fopen("DATABASE.txt", "wb")) == NULL) // open a stream from "countries"
    		err_sys("Open DATABASE Fail\n");

	if((FO2 = fopen("DIRECTORY.txt", "w+")) == NULL) // open a stream from "countries"
    		err_sys("Open DIRECTORY Fail\n");

    while ( fgets( (char *) Line,1000,FI) != NULL) // fill buffer up to newline or eof or error
    {

	Tok = strtok( Line ,",\n"); 	// skip ID number

        Tok = strtok( NULL ,",\n"); 	// this should get the country code 
        ActualStruct.code[0] = Tok[0];
        ActualStruct.code[1] = Tok[1];
        ActualStruct.code[2] = Tok[2];
        ActualStruct.code[3] = 0; 	// To create "string" 

	Tok = strtok( NULL ,",\n"); 	// this should get the country name 
        strncpy(&ActualStruct.name[0],Tok,50);	// copy string at most 50 chars

	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 
	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 

	Tok = strtok( NULL ,",\n"); 	// this should get the population
	ActualStruct.pop = atoi(Tok);	// convert string to integer

        Tok = strtok( NULL ,",\n"); 	// this one should get life expectancy
        ActualStruct.life_expectancy = atof(Tok);	// convert string to a floating point number

	strcpy(StructArray[i].code, ActualStruct.code);                  // get the current code 
	StructArray[i].offset = ftell(FO);                               // get the current offset in the DATABASE file 

	if (fwrite(&ActualStruct, sizeof(DATATYPE),1,FO) != 1)  // write the struct to the DATABASE file 
		err_sys("fwrite error");

	
	printf("%5s%50s%15u%18f%10u\n",&ActualStruct.code[0],&ActualStruct.name[0],ActualStruct.pop,ActualStruct.life_expectancy,StructArray[i].offset);

	i++;
	size = i;
	}
	


	printf("Before Sort:\n");
	for (i=0; i<size; i++)
	{
		printf("%s \t %u\n",StructArray[i].code, StructArray[i].offset);
	}	
	sort(StructArray,size);
	printf("After Sort:\n");
	for (i=0; i<size; i++)
	{	
	        printf("%s \t %u\n",StructArray[i].code, StructArray[i].offset);
	}

	if (fclose(FI))				// close file descriptor FI
		err_sys("Close error\n");	
	if (fclose(FO))				// close file descriptor FO
		err_sys("Close error\n");	
	if (fclose(FO2))			// close file descriptor FO2
		err_sys("Close error\n");


    	printf(" Made the break \n");  // and this if not error :) 

}

Open in new window


output:

--------------------------------------------------------------------------------------------------------
  CODE                   COUNTRY NAME                      POPULATION      LIFE EXPECTANCY    OFFSET
--------------------------------------------------------------------------------------------------------
  DZA                                           Algeria       31471000         69.699997         0
  AGO                                            Angola       12878000         38.299999        64
  BEN                                             Benin        6097000         50.200001       128
  BWA                                          Botswana        1622000         39.299999       192
  IOT                    British Indian Ocean Territory              0          0.000000       256
  BFA                                      Burkina Faso       11937000         46.700001       320
  BDI                                           Burundi        6695000         46.200001       384
Before Sort:
DZA      0
AGO      64
BEN      128
BWA      192
IOT      256
BFA      320
BDI      384
Segmentation Fault (core dumped)


I wish I could help you further. If you know how to use a debugger and step through the program, you will be able to confirm the values as they change.

The problem is that the program you are writing has some nice features in it requiring a decent knowlege of the C language. But you seem to have forgotten some of the earlier things that you learned. So, I recommend that you review in your textbook how to count in a loop; and review how to sort; and also review the concept of scope.

If you do not want to use the debugger, then add many print statements and make sure that each one is coming out correctly.

If you are stuck, then you can ask another more basic question, and someone will help you. I'll be back tonight to see how you have progressed.

Avatar of crazy4s

ASKER

i'm not familiar with debugger but when i try to run using gdb it gives me this at the end

Program received signal SIGSEGV, Segmentation fault.
0xff2b1a20 in strcpy () from /usr/lib/libc.so.1
Avatar of crazy4s

ASKER

I've made some changes on my sort function
void sort(INDEX SortArray[], int n)
{
	int j;
	for(j=0; j < n;j++)
	{
		int k;
		char *temp = SortArray[j].code;
		for (k= j-1; k >= 0; k--)
		{
			if(strcmp(SortArray[j].code, temp) >= 0)
				break;
			strcpy( SortArray[j+1].code, SortArray[j].code);
		}
		strcpy( SortArray[j+1].code,  temp); // strcpy	
	}
}

Open in new window


but the output is
--------------------------------------------------------------------------------------------------------
  CODE                   COUNTRY NAME                      POPULATION      LIFE EXPECTANCY    OFFSET
--------------------------------------------------------------------------------------------------------
  DZA                                           Algeria       31471000         69.699997         0
  AGO                                            Angola       12878000         38.299999        64
  BEN                                             Benin        6097000         50.200001       128
  BWA                                          Botswana        1622000         39.299999       192
  IOT                    British Indian Ocean Territory              0          0.000000       256
  BFA                                      Burkina Faso       11937000         46.700001       320
  BDI                                           Burundi        6695000         46.200001       384
Before Sort:
DZA      0
AGO      64
BEN      128
BWA      192
IOT      256
BFA      320
BDI      384
After Sort:
DZA      0
DZA      64
DZA      128
DZA      192
DZA      256
DZA      320
DZA      384
 Made the break

what i want is to be like this
After Sort:
AGO    64
BD1     384
BFA     320
...and so on

any help will be greatly appreciated:)
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of crazy4s

ASKER

oops sorry this is the new sort func
void sort(INDEX SortArray[], int n)
{
	int j;
	for(j=0; j < n;j++)
	{
		int k;
		char *temp = SortArray[j].code;
		for (k= j-1; k >= 0; k--)
		{
			if(strcmp(SortArray[k].code, temp) <= 0)
				break;
			strcpy(SortArray[k+1].code, SortArray[k].code);
		}
		strcpy( SortArray[k+1].code,  temp); // strcpy	
	}
}

Open in new window


however the output seems to be not much different

--------------------------------------------------------------------------------------------------------
  CODE                   COUNTRY NAME                      POPULATION      LIFE EXPECTANCY    OFFSET
--------------------------------------------------------------------------------------------------------
  DZA                                           Algeria       31471000         69.699997         0
  AGO                                            Angola       12878000         38.299999        64
  BEN                                             Benin        6097000         50.200001       128
  BWA                                          Botswana        1622000         39.299999       192
  IOT                    British Indian Ocean Territory              0          0.000000       256
  BFA                                      Burkina Faso       11937000         46.700001       320
  BDI                                           Burundi        6695000         46.200001       384
Before Sort:
DZA      0
AGO      64
BEN      128
BWA      192
IOT      256
BFA      320
BDI      384
After Sort:
DZA      0
DZA      64
DZA      128
DZA      192
IOT      256
IOT      320
IOT      384
------THE END------

well i still don't really understand on the p variable(gdb) as when i'm trying to make a breakpoint at sort and check by p temp(i dunno is it correct or not to type like this) but it gives me --> No symbol "temp" in current context???

Here is what I get:
Breakpoint 1, sort (SortArray=0x404120, n=7) at myprogram.c:27
27              for(j=0; j < n;j++)
(gdb) n
30                      char *temp = SortArray[j].code;
(gdb) n
31                      for (k= j-1; k >= 0; k--)
(gdb) p j
$1 = 0
(gdb) p temp
$2 = 0x404120 "DZA"
(gdb)

Open in new window

You have to execute the line (n) to see how a value changes.
Avatar of crazy4s

ASKER

where did you set for your breakpoint?
i get this when i set b sort
Breakpoint 1 at 0x10b24: file as2.c, line 43.
but it tells me --> The program is not being run.

Repeating..

The basic commands you need are:
b sort -- add breakpoint on the sort function before running the program
r -- run the program

So, just type in r
You need to do the b before the r so that when you run, the program will stop before completing.
Avatar of crazy4s

ASKER

hmm i don't get it why everytime it loops it compares all the country code but when come to this line the temp will be DZA???
strcpy( SortArray[k+1].code,  temp);
Good that you are now well into debugging and raising good issues. :)

In your OP, your question was about build errors.
After I helped you with that, you were able to run your program, but you were having trouble counting how many records were actually filled in.

After that question was straightened out, you did more testing and found that the results were not as desired.

The testing you did is called Black Box testing. It is a required methodology used to show that so-called working programs are really working.  Black Box testing is performed by independent testers, since the programmers tend to be biased.

As a programmer, you needed to learn about white box testing, which mean to open up the box (i.e., your program) and see what is going on inside.

You used gdb to do this, and now you are discovering a new set of problems. Good!

When I look at your sort function, I am not really seeing a bug, but a design flaw. So, I suggest that you review how to sort, and come up with a design using pseudo-code.

What has worked for others is to actually take a few cards out of a deck, and apply the algorithm's pseudo-code step-by-step on the cards to see if the cards got sorted correctly.

Once convinced that the algorithm is correct, then you need to implement it.

So, I suggest that you try to come up with a design that works. If you are having trouble doing that (by virtue of your white-box testing the algorithm's pseudo-code step-by-step on a small set of cards (say, 6), then you can ask for help in the Algorithms Zone.

The algorithms only get harder. So, it is important that you apply some methodology in getting it correct before you try to code it.

One more thing that will help you. As your assignments become more complicated, using gdb, IMO, is a bit clunky. I would find out what GUI debugger is available to you. If you need assistance with, say, installing ddd, then you can ask a question on that. If you then need assistance on how to use the GUI effectively, then you can ask another question on that as well.

So, for now, I recommend that you come up with an algorithm first (ask a question if you need help), and then try to implement once you know the design is correct (again, ask another question if you need help).
Oh, I forgot in the above, that we also dealt with the question of the "Segmentation Fault (core dumped)" issue that you found after we got the program built and running.

How are you coming along with your sort algorithm? There are a number of different kinds of sort algorithms. Which one are you are you required to use? Here is a Summary of popular sorting algorithms. The easiest ones to design are:
    Bubble sort
    Selection sort

Avatar of crazy4s

ASKER

I've to use an insertion sort... hmm so now i'm having problem in the sort so do you meant i need to open a new question again in algorithms section?
It depends on your level of understanding. If you can take 6 numbers, and sort them on paper using an insertion sort, then you won't have to do that. If you cannot, then the Algorithms zone is the place to go to learn how.

Here is a discussion of the Insertion Sort Algorithm and Pseudocode.

Assuming that you do understand the Insertion sort, take another stab at debugging paying special attention not just to the values as you did in http:#34935626 , but also the flow throgh the two loops. But, as I mentioned before, when using the debugger, it is beneficial to anticipate what should happen before each step in the function.

You found a good issue already in http:#34935626 ; see if you can find a good issue regarding the sequence of lines of code that you are executing.
Avatar of crazy4s

ASKER

I know how it flows and my code seems to be follow accordingly but i dunno how to solve it:'(
If you want to see a insertion sort video, here you go: http://www.youtube.com/watch?v=Fr0SmtN0IJM

When you go through the debugger, pay particular attention also to the values of the loop indices and the array indices.
But, at this junction, I think we worked together to get through a few questions - the build error in your OP, the counting of the actual number of records filled in, and the Segmentation Fault problem. We should keep the number of questions to one (as per EE policy). So, I think if you still have more questions, you can ask them; but try to limit a question to just one.
crazy4s,
It would be very beneficial for you to try to use a GUI debugger (and install one if you don't already have one). If you do use a GUI, I think you will see the problem much faster, maybe immediately. I know you are very busy, but this is an investment which will benefit you in the long run. I have a feeling that using gdb is not giving you a sense of the flow.