Reputation: 31
This is in C language, I'm trying to sort the data from the 2015 population in the text file in ascending order using a function and pointers to the array that I stored the state in. I want to try use a swapping algorithm within this function.
How do I sort the data using my ascensionOrder function from the 2015 population then output it in acending order?
Here is my code: `
#include <stdio.h>
#define FILENAME "PopulationData.txt"
int main(void)
{
void acensionOrder(int *populationData);
void replace(char*s, char a, char b);
char header[3][30];
char state[51][32];
int census[51][2];
FILE *myfile;
myfile = fopen(FILENAME,"r");
int x;
if (myfile== NULL)
{
printf("Errror opening file. \n");
}
else
{
fscanf(myfile, "%s%s%s", header[0], header[1], header[2]);
for (x = 0; x < 51; x++)
{
//fscanf(myfile, "%31s%d%d", state[x], &census[x][0], &census[x][1]); //testing
fscanf(myfile, "%*2c%s %d %d", state[x], &census[x][0], &census[x][1]); //Stores the text in the data file into array
replace(state[x], '_', ' '); //Replaces the lines
replace(state[x], '.', ' '); //Replaces the periods
//printf("%s\t%d\t%d\n", state[x], census[x][0], census[x][1]);
//printf("%2d %31s %10d %10d\n", x, state[x], census[x][0], census[x][1]); //Testing of sort
}
}
acensionOrder(&census[x][1]);
fclose(myfile);
//getchar();
//getchar();
return 0;
}
void acensionOrder(int *populationData) //This function sorts the 2015 data into ascending order
{
int j,k,m;
int sorted2015;
for(k=0; k<m; k++)
{
//m=k;
for(j=0; j<(m-1); j++)
{
if(*(populationData+j)<*(populationData+m))
//m=j;
sorted2015=*(populationData+m);
*(populationData+m)=*(populationData+k);
*(populationData+k)=sorted2015;
}
}
printf("%d\n", sorted2015);
}
void replace(char*s, char a, char b) //This function uses pointers to find characters
{
for(;*s; s++)
{
if(*s==a)*s = b;
}
}
`
Here is the text file the program reads from: Text file for US population
Upvotes: 2
Views: 1379
Reputation: 84551
I'm trying to sort the data from the 2015 population in the text file in ascending order using a function and pointers to the array
As a number of comments have pointed out, you can accomplish your stated goal simply by using the qsort
algorithm. The comparison function you write for qsort
will accept a pointer to an element within any type of array of objects you pass to it. In your case, holding the data in an array of struct containing the name of the state, the census and estimate would make things quite easy. You could use a simple struct with a single character array (24-char will hold your longest name) and two integers. Adding a typedef
to stcen
for your state census is for convenience, e.g.
typedef struct { /* structure with name census and estimate */
char name[NMLEN];
int cen, est;
} stcen;
Using qsort
, you simply want an ascending sort on an integer value, which for a standard integer array would take the form:
int cmpint (const void *a, const void *b)
{
/* (a > b) - (a < b) */
return (*(int *)a > *(int *)b) - (*(int *)a < *(int *)b);
}
which if you prefer to cast before the return, it is just shorthand for:
const int ia = *(const int *)a; // casting pointer types
const int ib = *(const int *)b;
return (ia > ib) - (ia < ib);
(returning the difference of the comparison, avoids potential for overflow)
Using an array of struct is no different, you simply dereference the pointers passed to the comparison function until you are referencing the integer value you wish to sort by, e.g. in the case above:
/* integer comparison of struct on 'cen' */
int cmpcen (const void *a, const void *b) {
return ((((stcen *)a)->cen > ((stcen *)b)->cen) -
(((stcen *)a)->cen < ((stcen *)b)->cen));
}
The remainder is just reading your data from your data file, discarding the heading row, and storing the remaining values in your array of struct. Since you know you have 51
states, your longest state name will fit in 24-chars
(and a formatting integer width of 9-chars
to make printing pretty) you can use an enum
to specify the constants for your program. Putting the pieces together, you can do something similar to the following:
#include <stdio.h>
#include <stdlib.h>
enum { IWDTH = 9, NMLEN = 24, NSTATE = 51 }; /* constants used */
typedef struct { /* structure with name, census and estimate */
char name[NMLEN];
int cen, est;
} stcen;
/* integer comparison of struct on 'cen' */
int cmpcen (const void *a, const void *b) {
return ((((stcen *)a)->cen > ((stcen *)b)->cen) -
(((stcen *)a)->cen < ((stcen *)b)->cen));
}
int main (int argc, char **argv) {
int i = 0, ndx = 0; /* general i, index */
stcen census[NSTATE] = {{ .name = "" }}; /* array of struct */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "file open failed '%s'\n", argv[1]);
return 1;
}
fscanf (fp, "%*[^\n]%*c"); /* strip header line */
/* read each line, input to struct, advance index */
while (ndx < NSTATE && fscanf (fp, " %s %d %d",
census[ndx].name, &census[ndx].cen, &census[ndx].est) == 3) {
ndx++;
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
qsort (census, ndx, sizeof *census, cmpcen); /* sort on census */
for (i = 0; i < ndx; i++) /* output results */
printf (" %-*s %*d %*d\n", NMLEN, census[i].name,
IWDTH, census[i].cen, IWDTH, census[i].est);
return 0;
}
The program simply expects the name of the file to read data from as the first argument (or it will read from stdin
if no argument is given). Applied to your data, you get:
Example Use/Output
$ ./bin/census < ../dat/census.txt
Wyoming 563626 586107
District_of_Columbia 601723 672228
Vermont 625741 626042
North_Dakota 672591 756927
Alaska 710231 738432
South_Dakota 814180 858469
Delaware 897934 945934
Montana 989415 1032949
Rhode_Island 1052567 1056298
New_Hampshire 1316470 1330608
Maine 1328361 1329328
Hawaii 1360301 1431603
Idaho 1567582 1654930
Nebraska 1826341 1896190
West_Virginia 1852994 1844128
<snip>
Look things over and consider the qsort
approach instead of rolling-your-own sort routine. The chances are very good that qsort
will be much more efficient and less prone to errors. Let me know if you have any questions.
Upvotes: 1
Reputation: 11
#include <stdio.h>
#define FILENAME "C:\\PopulationData.txt"
#define NUM 51
int main(void)
{
void acensionOrder(int *populationData);
void replace(char*s, char a, char b);
char header[3][30];
char state[NUM][32];
int census[2][NUM];
FILE *myfile;
myfile = fopen(FILENAME, "r");
int x;
if (myfile == NULL)
{
printf("Errror opening file. \n");
}
else
{
fscanf(myfile, "%s%s%s", header[0], header[1], header[2]);
for (x = 0; x < NUM; x++)
{
//fscanf(myfile, "%31s%d%d", state[x], &census[x][0], &census[x][1]); //testing
fscanf(myfile, "%*2c%s %d %d", state[x], &census[0][x], &census[1][x]); //Stores the text in the data file into array
replace(state[x], '_', ' '); //Replaces the lines
replace(state[x], '.', ' '); //Replaces the periods
//printf("%s\t%d\t%d\n", state[x], census[x][0], census[x][1]);
//printf("%2d %31s %10d %10d\n", x, state[x], census[x][0], census[x][1]); //Testing of sort
}
}
acensionOrder(&census[1][0]);
fclose(myfile);
getchar();
getchar();
return 0;
}
void acensionOrder(int *populationData) //This function sorts the 2015 data into ascending order
{
int j, k, m;
m = NUM;
int sorted2015;
for (k = 0; k<m; k++)
{
//m=k;
for (j = k+1; j<m; j++)
{
if (*(populationData + j) < *(populationData + k ))
{
sorted2015 = *(populationData + j);
*(populationData + j ) = *(populationData + k);
*(populationData + k) = sorted2015;
}
//m=j;
}
}
for (k = 0; k<m; k++)
printf("%d ", *(populationData + k));
}
void replace(char*s, char a, char b) //This function uses pointers to find characters
{
for (; *s; s++)
{
if (*s == a)*s = b;
}
}
Upvotes: 0
Reputation: 1902
There was a couple of bugs in your program especially in the acensionOrder()
function which I completely changed it to a bubbleSort()
that keeps swapping the array elements until it is sorted. Keep in mind bubbleSort()
is easy but expensive. So, you may want to change it to a o(nlogn)
sorting algorithm like quicksort()
or mergesort()
. Now, let's see what do you need to add to make your program sort the input file.
Before reaching the main()
function you need to import some standard C libraries and also declare your function signatures. Previously, you put the function signatures in the main()
function which was wrong.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FILENAME "PopulationData.txt"
void bubbleSort(int arr1[][2], char arr2[][32], int len);
void replace(char *s, char a, char b);
For main()
, make sure to add the argc
, *argv[]
arguments. Basically, in the main()
function, we open the file, start parsing each line using fscanf()
, trim the .
and _
characters, close the file, call the bubbleSort()
and finally print the sorted results.
int main(int argc, char *argv[])
{
char header[3][30];
memset(header, 0, sizeof(header[0][0]) * 3 * 30);
char state[51][32];
memset(state, 0, sizeof(state[0][0]) * 51 * 32);
int census[51][2];
memset(census, 0, sizeof(census[0][0]) * 51 * 2);
FILE *myfile;
myfile = fopen(FILENAME,"r");
int x;
if (myfile== NULL)
{
printf("Errror opening file. \n");
return(1);
}
fscanf(myfile, "%s %s %s", header[0], header[1], header[2]);
printf("%s %s %s\n",header[0], header[1], header[2]);
for (x = 0; x < 51; x++)
{
fscanf(myfile, "%*2c%s %d %d", state[x], &census[x][0], &census[x][1]);
replace(state[x], '_', ' ');
replace(state[x], '.', ' ');
printf("[%02d] %20s: %8d %8d\n", x, state[x], census[x][0], census[x][1]);
}
fclose(myfile);
bubbleSort(census, state, 51);
printf("%s %s %s\n",header[0], header[1], header[2]);
for(x = 0; x < 51; x++)
{
printf("[%02d] %20s: %8d %8d\n", x, state[x], census[x][0], census[x][1]);
}
return(0);
}
The next part is the abubbleSort()
implementation. It accepts the census and state arrays along with their length and starts sorting them based on the second dimension of census (censos[j][1]
) which contains the 2015 population. Each time, we want to replace an element in censos[j][1]
, we need to replace the corresponding elements in censos[j][0]
and state[j]
.
void bubbleSort(int arr1[][2], char arr2[][32], int len)
{
int i;
int j;
int tmp0;
int tmp1;
char tmp2[32];
memset(tmp2, '\0',32);
for(i = len - 1; i >= 0; i--)
{
for(j = 0; j < i; j++)
{
if(arr1[j][1] > arr1[j+1][1])
{
tmp0 = arr1[j+1][0];
tmp1 = arr1[j+1][1];
strncpy(tmp2, arr2[j+1], 32);
arr1[j+1][0] = arr1[j][0];
arr1[j+1][1] = arr1[j][1];
strncpy(arr2[j+1], arr2[j], 32);
arr1[j][0] = tmp0;
arr1[j][1] = tmp1;
strncpy(arr2[j], tmp2, 32);
memset(tmp2, '\0',32);
}
}
}
}
And this is your replace()
function which I'm pasting it here AS IS.
void replace(char*s, char a, char b)
{
for(;*s; s++)
{
if(*s==a)*s = b;
}
}
Finally, since you're dealing with strings, you may notice that I extensively use memset()
to make the array elements NULL terminated to avoid plausible printing problems with printf()
function.
Upvotes: 2