c - How to sort lines of file depending on value at end of each line -
i'm trying create program takes input file , sorts new output file in ascending order depending on number @ end of each line. example, if input file contains 3 lines below:
a man 50 65 better 7
the corresponding sorted output file 3 lines sorted:
better 7 man 50 65
code have far:
int sortlines(char * inputfilename, char * outputfilename) { file *fpin = fopen(inputfilename, "r");//open file to read if (!fpin) { printf("error in file opening\n"); exit (-1); } file *fpout = fopen(outputfilename, "w");//open file to write if (!fpout) { printf("error in opfile opening\n"); exit (-1); } char file[10][1024]; int = 0; while(fgets(file[i], sizeof(file[i]), fpin)) i++; int total = i; for(i = 0; i<total; ++i) printf("%s", file[i]); return 0; }
continuing on comment, can read lines struct (containing line , int), use strrchr
find last space in each line (or if null, take whole line), convert string strtol
or atoi
or set int
field of struct. simple matter of sorting structs based on int
member. i'll leave reading struct you, sorting example is:
#include <stdio.h> #include <stdlib.h> #define maxl 32 struct data { char line[maxl]; int n; }; int compare_n (const void *a, const void *b) { struct data *ia = (struct data *)a; struct data *ib = (struct data *)b; return (int)(ia->n - ib->n); } int main (void) { struct data lines[] = {{"a man 50", 50}, {"65", 65}, {"better 7", 7}}; size_t nstr = sizeof lines / sizeof *lines; size_t = 0; qsort (lines, nstr, sizeof *lines, compare_n); (i = 0; < nstr; i++) printf (" %s\n", lines[i].line); return 0; }
output
$ ./bin/struct_sort_int better 7 man 50 65
full example
#include <stdio.h> #include <stdlib.h> #include <string.h> #define maxl 64 /* simple struct holding char array , int */ struct data { char line[maxl]; int n; }; /* qsort comparison function int 'n' */ int compare_n (const void *a, const void *b) { struct data *ia = (struct data *)a; struct data *ib = (struct data *)b; return (int)(ia->n - ib->n); } int main (int argc, char **argv) { if (argc < 2 ) { /* validate @ least 1 argument provided */ fprintf (stderr, "error: insufficient input, usage: %s filename\n", argv[0]); return 1; } struct data lines[maxl] = {{{0}, 0}}; /* array of struct */ char *ln = null; /* buffer getline, getline allocates */ size_t n = 0; /* initial size of buf, 0 getline decides */ ssize_t nchr = 0; /* getline return, no. of chars read */ size_t idx = 0; /* index array of struct */ size_t = 0; /* general iteration variable */ file *fp = null; /* file pointer input file */ if (!(fp = fopen (argv[1], "r"))) { /* validate file open */ fprintf (stderr, "error: file open failed. '%s'\n", argv[1]); return 1; } /* read each line in file */ while ((nchr = getline (&ln, &n, fp)) != -1) { while (nchr > 0 && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r')) ln[--nchr] = 0; /* strip newline or carriage rtn */ if (!nchr) continue; /* skip blank lines */ if (nchr > maxl - 1) { /* test line > maxl -1 */ fprintf (stderr, "warning: line exceeded %d chars.\n", maxl); continue; /* number @ end invalid */ } strcpy (lines[idx].line, ln); /* copy struct.line */ char *p = null; if (!(p = strrchr (ln, ' '))) /* pointer last space */ p = ln; /* if no space, line */ lines[idx].n = atoi (p); /* convert string int */ idx++; /* increment index */ if (idx == maxl) { /* if maxl read, break */ fprintf (stderr, "warning: %d lines read.\n", maxl); break; } } if (fp) fclose (fp); /* close input file */ if (ln) free (ln); /* free line buffer mem */ qsort (lines, idx, sizeof *lines, compare_n); /* sort struct */ (i = 0; < idx; i++) /* print sorted array */ printf (" %s\n", lines[i].line); return 0; }
take , let me know if have questions. data in file dat/endno.txt
test. i'll add comments when chance.
note: updated skip blank lines , check line length against maxl
eliminate possibility of write beyond end of lines , skip lines truncated rendering number @ end invalid.
without struct
statically allocated arrays
the following example uses 2 2d arrays, 1 lines
, 1 holding original line index , number @ end of line. unlike dynamically allocated example below, example limited reading maxl
lines file or no more maxs
characters each. if line maxs
characters long (including null-terminator), must discarded, because there no way of knowing if number @ end remains valid. 2d array containing line index , number @ end sorted based on number @ end, lines printed based on original line index resulting in lines printing in sorted order number @ end. while may simpler, far more limited method utilizing struct
or dynamically allocated approach below. can think going. luck. drop line if have questions.
#include <stdio.h> #include <stdlib.h> #include <string.h> #define maxl 64 #define maxs 128 int cmpint (const void *a, const void *b); int main (int argc, char **argv) { if (argc < 2 ) { /* validate @ least 1 argument provided */ fprintf (stderr, "error: insufficient input, usage: %s filename\n", argv[0]); return 1; } int numidx[maxl][2] = {{0}}; /* array of integers */ char lines[maxl][maxs] = {{0}}; /* array of strings */ char ln[maxs] = {0}; /* buffer fgets, maxs in length */ ssize_t nchr = 0; /* getline return, no. of chars read */ size_t idx = 0; /* index array of struct */ size_t = 0; /* general iteration variable */ file *fp = null; /* file pointer input file */ if (!(fp = fopen (argv[1], "r"))) { /* validate file open */ fprintf (stderr, "error: file open failed. '%s'\n", argv[1]); return 1; } /* read each line in file */ while (fgets (ln, maxs, fp) != null) { nchr = strlen (ln); /* length of ln */ while (nchr > 0 && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r')) ln[--nchr] = 0; /* strip newline or carriage rtn */ if (!nchr || nchr == maxs - 2) /* skip blank lines + full */ continue; /* lines (end no. invalid) */ strcpy (lines[idx], ln); /* copy ln lines[idx] */ char *p = null; if (!(p = strrchr (ln, ' '))) /* pointer last space */ p = ln; /* if no space, line */ numidx[idx][0] = atoi (p); /* save end no. in array */ numidx[idx][1] = idx; /* save line index in array */ idx++; /* increment index */ if (idx == maxl) { /* if maxl read, break */ fprintf (stderr, "warning: %d lines read.\n", maxl); break; } } fclose (fp); qsort (numidx, idx, sizeof (int) * 2, cmpint);/* sort array */ (i = 0; < idx; i++) /* print sorted array */ printf (" %s\n", lines[numidx[i][1]]); return 0; } /* qsort integer compare function */ int cmpint (const void *pa, const void *pb ) { const int *a = pa; const int *b = pb; if (a[0] < b[0]) return -1; return (b[0] < a[0]); }
without struct
, dynamically allocated arrays
to around using structure hold string number, can use 2 arrays. 1 hold strings, , 2d array holding original line index , number @ end of line (2 integers). qsort
integer array on (number @ end) element, loop through each line printing out lines in sorted order based on line index value of sorted array. set handle lines of length , reallocate number of lines (in each array) needed. since dynamic allocation may bit much, i'm working on static array version well, tomorrow before have time. here first version:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define maxl 64 int cmpint (const void *a, const void *b); char **realloc_char (char **sp, size_t *n); int **realloc_int (int **ip, size_t *n); int main (int argc, char **argv) { if (argc < 2 ) { /* validate @ least 1 argument provided */ fprintf (stderr, "error: insufficient input, usage: %s filename\n", argv[0]); return 1; } int **numidx = null; /* array of pointers-to-pointer-to-int */ char **lines = null; /* array of pointer-to-pointer-to-char */ char *ln = null; /* buffer getline, getline allocates */ size_t n = 0; /* initial size of buf, 0 getline decides */ ssize_t nchr = 0; /* getline return, no. of chars read */ size_t idx = 0; /* index array of struct */ size_t = 0; /* general iteration variable */ size_t maxl = maxl; /* holds current allocation size of arrays */ file *fp = null; /* file pointer input file */ if (!(fp = fopen (argv[1], "r"))) { /* validate file open */ fprintf (stderr, "error: file open failed. '%s'\n", argv[1]); return 1; } /* allocate maxl pointers int* */ if (!(numidx = calloc (maxl, sizeof *numidx))) { fprintf (stderr, "error: memory allocation failed.\n"); return 1; } /* allocate maxl pointers char* */ if (!(lines = calloc (maxl, sizeof *lines))) { fprintf (stderr, "error: memory allocation failed.\n"); return 1; } /* read each line in file */ while ((nchr = getline (&ln, &n, fp)) != -1) { while (nchr > 0 && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r')) ln[--nchr] = 0; /* strip newline or carriage rtn */ if (!nchr) continue; /* skip blank lines */ lines[idx] = strdup (ln); /* copy ln lines[idx] */ /* allocate space 2 int @ numidx[idx] */ if (!(numidx[idx] = calloc (2, sizeof **numidx))) { fprintf (stderr, "error: memory allocation failed.\n"); return 1; } char *p = null; if (!(p = strrchr (ln, ' '))) /* pointer last space */ p = ln; /* if no space, line */ numidx[idx][0] = atoi (p); /* save end no. in array */ numidx[idx][1] = idx; /* save line index in array */ idx++; /* increment index */ if (idx == maxl) { /* if idx = maxl reallocate */ size_t tsz = maxl; /* tmp var, each maxl */ numidx = realloc_int (numidx, &tsz); lines = realloc_char (lines, &maxl); } } if (ln) free (ln); fclose (fp); qsort (numidx, idx, sizeof *numidx, cmpint); /* sort struct */ (i = 0; < idx; i++) /* print sorted array */ printf (" %s\n", lines[numidx[i][1]]); (i = 0; < idx; i++) { /* free allocated memory */ free (numidx[i]); free (lines[i]); } free (numidx); free (lines); return 0; } /* qsort integer compare function */ int cmpint (const void *a, const void *b) { const int **ia = (const int **)a; const int **ib = (const int **)b; return (*ia)[0] - (*ib)[0]; } /** realloc array of pointers strings setting memory 0. * reallocate array of character arrays setting * newly allocated memory 0 allow iteration */ char **realloc_char (char **sp, size_t *n) { char **tmp = realloc (sp, 2 * *n * sizeof *sp); if (!tmp) { fprintf (stderr, "error: struct reallocation failure.\n"); // return null; exit (exit_failure); } sp = tmp; memset (sp + *n, 0, *n * sizeof *sp); /* memset new ptrs 0 */ *n *= 2; return sp; } /** realloc array of pointers int* setting memory 0. * reallocate array of integer arrays setting * newly allocated memory 0 allow iteration */ int **realloc_int (int **ip, size_t *n) { int **tmp = realloc (ip, 2 * *n * sizeof *ip * 4); if (!tmp) { fprintf (stderr, "error: struct reallocation failure.\n"); // return null; exit (exit_failure); } ip = tmp; memset (ip + *n, 0, *n * sizeof *ip * 4); /* memset new ptrs 0 */ *n *= 2; return ip; }
Comments
Post a Comment