How to fill array with elements in a .txt file - c

I have a dynamic 2D float array and a file with both strings, integers(number of floats in the line) and float numbers.
M = (float**)malloc(num_lines * sizeof(float));
for(int i = 0; i < num_lines; i++){
M[i] = (float*)malloc(num_columns * sizeof(float));
}
Example:
2
John 3 5.5 89.5 30.67 0.00
Mary 4 78.9 67.4 67.3 9.0 0.00
(null)
The number of lines is the one on the file + 1 and the number of columns is the highest integer + 1 (5 in this case) because the 0.00 marks the end of each line.
How do I load only the floats into memory? I've tried different types of loops with fgets and strtok but it doesn't work due to the different types of variables.
The code is like this:
for(int i = 0; i < num_lines; i++){
fgets(buf, 1000, aux);
name = strtok(buf, " ");
col = atoi(strtok(NULL, " "));
for(j = 0; j < num_columns; j++){
M[i][j] = atof(strtok(NULL, " "));
if(M[i][j] == 0.00){
break;
}
}
}

This sort of parsing is a bit of a pain, but is a good exercise to do every now and again. This is relatively easy with scanf, but scanf is not suitable for anything but toys. (It is literally impossible to correctly handle anything robustly, since even a simple "%d" format specifier leads to undefined behavior on certain input.) Unless you are willing to read the file twice to determine the maximum size of a column, you can't preallocate the entire array. Instead of that, I would suggest doing something like:
#include <ctype.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* sample input
2
John 3 5.5 89.5 30.67 0.00
Mary 4 78.9 67.4 67.3 9.0 0.00
*/
FILE * xfopen(const char *, const char *);
void * xmalloc(size_t);
int get_row_count(FILE *in, char **line, size_t *cap, const char *name);
float * parse_line(const char *s, int lc);
int
main(int argc, char **argv)
{
int lc = 0;
char *line = NULL;
size_t cap = 0;
FILE *in = argc > 1 ? xfopen(argv[1], "r") : stdin;
int rows = get_row_count(in, &line, &cap, argv[1]);
float **M = xmalloc(rows * sizeof *M);
for( lc = 0; lc < rows && getline(&line, &cap, in) > 0; lc += 1 ){
M[lc] = parse_line(line, lc + 1);
}
if( lc != rows ){
warnx("invalid input: missing some rows");
}
for( int i = 0; i < lc; i++ ){
float *f = M[i];
for( int j = 0; j < f[0]; j++ ){
printf("%f\t", f[j + 1]);
}
putchar('\n');
}
}
float *
parse_line(const char *s, int lc)
{
/* Skip the name */
char *end;
while( *s && ! isspace(*s) ){
s += 1;
}
int siz = strtol(s, &end, 10);
if( siz <= 0 || ! isspace(*end) ){
errx(EXIT_FAILURE, "Invalid input on line %d", lc);
}
float *f = xmalloc((1 + siz) * sizeof *f);
f[0] = siz;
for( int i = 1; i < siz + 1; i += 1 ){
f[i] = strtof(end, &end);
}
while( isspace(*end) ){
end += 1;
}
if( *end == '\0' || strcmp(end, "0.00\n") ){
errx(EXIT_FAILURE, "Invalid input on line %d", lc);
}
return f;
}
int
get_row_count(FILE *in, char **line, size_t *cap, const char *name)
{
if( getline(line, cap, in) <= 0 ){
if( feof(in) ){
errx(EXIT_FAILURE, "Empty input");
} else {
err(EXIT_FAILURE, "%s", name);
}
}
char *end;
int rows = strtol(*line, &end, 10);
if( rows <= 0 ){
errx(EXIT_FAILURE, "invalid row count: %d", rows);
}
if( *end != '\n' ){
errx(EXIT_FAILURE, "unexpected input on line 1");
}
return rows;
}
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
*mode == 'r' ? stdin : stdout;
if( fp == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
void *
xmalloc(size_t s)
{
void *rv = malloc(s);
if( rv == NULL ){
perror("malloc");
exit(EXIT_FAILURE);
}
return rv;
}

Related

How to open a txt file and allocate its contents to a 2D array?

So I have a txt file that represents a matrix. what I need to do is open it up and allocate its contents to a Matrix.
For example:
in my txt file I have:
39 -1 -42 -42
-6 -46 89 86
76 -62 35 92
-20 24 -10 38
52 1 -86 41
I need to open up a file read its content and allocate each value respectively into a matrix.
I tried this, however, I still can not accesses a single element. I was thinking to use strtok() to break up the line into tokens as my backup plan but I am sure there should be a better way.
int matrix[4][5];
FILE *files;
char str[100];
files = fopen("./matrix-samples/m-5-10-a.txt", "r");
if(files == NULL) {
printf("%s\n","error" );
}
else{
for (int i = 0; i < 5; i++) {
fgets (str, 60, files);
printf("%s", str);
}
}
return 0;
}
Do not use strtok. The 9th circle of hell contains 3 functions: gets, scanf, and strtok. Just avoid it. Read the data with fgets, and parse it with something from the strtol family. For example:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#define ROW 5
#define COL 4
static void
die(int row, int col)
{
fprintf(stderr, "Invalid input in row %d, near column %d\n", row, col);
exit(1);
}
int
main(int argc, char **argv)
{
const char *path = argc > 1 ? argv[1] : "matrix-samples/m-5-10-a.txt";
int matrix[ROW][COL];
FILE *ifp = fopen(path, "r");
char str[256];
if( ifp == NULL ){
perror(path);
return EXIT_FAILURE;
}
int row = 0;
while( row < ROW && fgets(str, sizeof str, ifp ) != NULL ){
char *p = str;
for( int col = 0; *p && col < COL; col += 1 ){
char *end;
matrix[row][col] = strtol(p, &end, 10);
if( ! isspace(*end) ){
die(row, end - str);
}
p = end + 1;
}
while( isspace(*p) ){
p += 1;
}
if( *p || p[-1] != '\n' ){
die(row, p - str);
}
row += 1;
}
if( fgetc(ifp) != EOF ){
die(row, 0);
}
for( int i = 0; i < ROW; i++ ){
for( int j = 0; j < COL; j++ ){
printf("%7d", matrix[i][j]);
}
putchar('\n');
}
return 0;
}

Read 2 files in C to calculate Manhattan Distance

I need some help just starting off my code for this program. This is my first time reading a file in c and I have been stuck starting it off. Essentially, I need to read in two files to calculate Manhattan Distance and output the ID for each file and the closest distance. The files look something like this:
3,2
0, 3.4, 4.3
1, 4.5, 6.1
2, 7.2, 3.9
3,2
0, 5.9, 6.7
1, 8.5, 1.2
2, 9.8, 4.9
My current code only outputs the table and I am trying to find a way to use columns as a way to calculate Manhattan distance. The 3,2 signifies the rows and columns and the 0,1,2 are the IDs. Here is the current code I have found online and modified a bit that I thought may be useful.
#include <stdio.h>
#include <string.h>
int main()
{
FILE* testFile = fopen("Test.txt", "r");
if (!testFile)
printf("Can't open file\n");
else {
char buffer[1024];
int row = 0;
int column = 0;
while (fgets(buffer, 1024, testFile)) {
column = 0;
row++;
if (row == 1)
continue;
// Splitting the data
char* value = strtok(buffer, ", ");
while (value) {
// Column 1
if (column == 0) {
printf("TestID:");
}
// Column 2
if (column == 1) {
printf("\tx1: ");
}
// Column 3
if (column == 2) {
printf("\ty1: ");
}
printf("%s", value);
value = strtok(NULL, ", ");
column++;
}
printf("\n");
}
// Close the file
fclose(testFile);
}
return 0;
}
Here's a basic example demonstrating one method of parsing your input files with strtod and strtoul:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct mat {
int rows;
int columns;
double *data;
};
void
show(const struct mat *A)
{
double *d = A->data;
for( int i = 0; i < A->rows; i += 1 ){
for( int j = 0; j < A->columns; j += 1 ){
printf("%f\t", *d++);
}
putchar('\n');
}
}
/*
* Return nonzero if the first non-whitespace
* character after *e is not v. Terminate search
* at a newline.
*/
int
expect_next(char **e, const char v)
{
char *end = *e;
while( isspace(*end) && *end != '\n' ){
end += 1;
}
*e = end + 1;
return *end != v;
}
int
get_data(struct mat *A, const char *path)
{
unsigned line = 1;
FILE* testFile = fopen(path, "r");
if( testFile == NULL ){
perror(path);
return 0;
}
char buffer[1024];
char *end = buffer;
if( fgets(buffer, sizeof buffer, testFile) == NULL ){
if( ferror(testFile) ){
perror(path);
} else {
goto bad_input;
}
return 0;
}
A->rows = strtoul(buffer, &end, 10);
if( expect_next(&end, ',') ){
goto bad_input;
}
A->columns = strtoul(end, &end, 10);
if( expect_next(&end, '\n') ){
goto bad_input;
}
A->data = malloc(A->rows * A->columns * sizeof *A->data);
if( A->data == NULL ){
perror("malloc");
return 0;
}
double *val = A->data;
unsigned row = 0;
while( NULL != fgets(buffer, sizeof buffer, testFile) ){
line += 1;
unsigned v = strtoul(buffer, &end, 10);
if( v != row ){
goto bad_input;
}
if( expect_next(&end, ',') ){
goto bad_input;
}
unsigned col = 0;
while( col < A->columns && *end ){
*val++ = strtod(end, &end);
if( expect_next(&end, ++col == A->columns ? '\n' : ',') ){
goto bad_input;
}
}
if( col != A->columns ){
goto bad_input;
}
row += 1;
}
if( row != A->rows ){
goto bad_input;
}
if( fclose(testFile) ){
perror(path);
}
return 1;
bad_input:
fprintf(stderr, "%s: Invalid input at line %u, column %u\n", path,
line, (unsigned)(end - buffer));
return 0;
}
int
main(int argc, char ** argv)
{
char *args[] = { NULL, "/dev/stdin", NULL };
if( argc < 2 ){
argv = args;
}
for( argv += 1; *argv; argv += 1 ){
struct mat A;
if( get_data(&A, *argv) ){
show(&A);
}
}
}

One file to another file conversion in C

I have an input file named as datafile.data, which looks something like below:
1,2,1,1,0
1,3,1,1,0
1,1,2,2,1
2,1,2,2,1
2,3,2,3,1
1,1,2,3,2
3,1,1,4,2
2,1,3,2,2
3,3,3,1,2
2,2,3,4,2
Here the 1st 4 columns stands for 4 attribute values say A1, A2, A3, A4. And the final column stands for the class value. For this particular sample file there are 4 attributes but for some other files, there can be 'n' number of attributes but for every file, the last column will give the class values.
Now I want to convert this file to another file named as : outputfile.exp
Where the output file's 1st row looks something like below:
<Number of rows in the .data file> <Number of attributes> <Max value of A1> <Max value of A2> <Max value of A3> <Max value of A4> <(Max value of last column)+1>
And the remaining rows of the output file will be same as the data file, with just one change, that is the last column's each value will be incremented by 1.
For an example the output file for the above example will look like:
10 4 3 3 3 4 3
1,2,1,1,1
1,3,1,1,1
1,1,2,2,2
2,1,2,2,2
2,3,2,3,2
1,1,2,3,3
3,1,1,4,3
2,1,3,2,3
3,3,3,1,3
2,2,3,4,3
Where the 1st row's 10 is the number of rows, 4 is the number of attributes present, (3,3,3,4) these 4 are the maximum values of attributes A1,A2,A3 and A4 and last 3 stands for the highest class value +1. And the last column's every value has been incremented by 1 as well.
Below I am attaching my try:
#include <stdio.h>
#include <string.h>
#define MAX_FILE_NAME 100
int main()
{
FILE *fp;
int count = 0; // Line counter (result)
char filename[MAX_FILE_NAME], dataToBeRead[50];
char c; // To store a character read from file
// Open the file
fp = fopen("datafile.data", "r");
// Check if file exists
if (fp == NULL)
{
printf("Could not open file %s", filename);
return 0;
}
// Extract characters from file and store in character c
for (c = getc(fp); c != EOF; c = getc(fp))
if (c == '\n') // Increment count if this character is newline
count = count + 1;
fclose(fp);
printf("%d\n",count);
fp = fopen("datafile.data", "r");
if ( fp == NULL )
{
printf( "Failed to open." ) ;
}
else
{
while( fgets ( dataToBeRead, 50, fp ) != NULL )
{
printf( "%s" , dataToBeRead ) ;
}
fclose(fp) ;
}
return 0;
}
And I am getting the below output:
10
1,2,1,1,1
1,3,1,1,1
1,1,2,2,2
2,1,2,2,2
2,3,2,3,2
1,1,2,3,3
3,1,1,4,3
2,1,3,2,3
3,3,3,1,3
2,2,3,4,3
Now I am unable to proceed further, as I am very new to C, please help me out.
Edit 1 : The output format of the example will be:
10 4 3 3 3 4 3
1 2 1 1 1
1 3 1 1 1
1 1 2 2 2
2 1 2 2 2
2 3 2 3 2
1 1 2 3 3
3 1 1 4 3
2 1 3 2 3
3 3 3 1 3
2 2 3 4 3
You really don't want to do this, since rewinding an input stream is an anti-pattern. But you can do something like:
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE * xfopen(const char *path, const char *mode);
void * xmalloc(size_t s);
void
parse_line(const char *buf, int *max, int column_count)
{
for(int i = 0; i < column_count; i++ ){
char *end;
int t = strtol(buf, &end, 10);
if( t > max[i] ){
max[i] = t;
}
if( !((i < column_count - 1 && *end == ',')
|| (i == column_count - 1 && *end == '\n'))
){
fprintf(stderr, "invalid input '%c' in %s", *end, buf);
exit(1);
}
buf = end + 1;
}
}
int
main(int argc, char **argv)
{
const char *path = argc > 1 ? argv[1] : "stdin";
FILE *in = argc > 1 ? xfopen(path, "r") : stdin;
char buf[1024];
int column_count = 1;
int row_count = 1;
int *max;
/* Read first line to determine number of columns */
if( fgets(buf, sizeof buf, in) == NULL ){
fputs("Input error\n", stderr);
return 1;
}
for( const char *p = buf; *p; p++ ){
if( *p == ',' ){
column_count += 1;
}
}
max = xmalloc(column_count * sizeof *max);
for( int i = 0; i < column_count; i++ ){
max[i] = INT_MIN;
}
parse_line(buf, max, column_count);
while( fgets(buf, sizeof buf, in) != NULL ){
row_count += 1;
parse_line(buf, max, column_count);
}
if( fseek(in, 0L, SEEK_SET) ){
perror(path);
return 1;
}
printf("%d %d ", row_count, column_count - 1);
for( int i = 0; i < column_count - 1; i += 1 ){
printf("%d ", max[i]);
}
printf("%d\n", max[column_count - 1] + 1);
while( fgets(buf, sizeof buf, in) != NULL ){
char *comma = strrchr(buf, ',');
if( comma == NULL ){
fprintf(stderr, "Invalid input\n");
return 1;
}
*comma = '\0';
int k = strtol(comma + 1, NULL, 10);
printf("%s,%d\n", buf, k + 1);
}
}
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
*mode == 'r' ? stdin : stdout;
if( fp == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
void *
xmalloc(size_t s)
{
void *rv = malloc(s);
if( rv == NULL ){
perror("malloc");
exit(EXIT_FAILURE);
}
return rv;
}
You can execute this as ./a.out < datafile.data > outputfile.exp or ./a.out datafile.data > outputfile.exp, but this will not work if you try to read from a pipe (the seek will fail). The seek failure and the inability to run this as a filter make this a suboptimal approach, but storing the entire file in memory also has drawbacks.
As William Pursell has provided superb answer in C, here is an awk alternative, although awk is not tagged.
awk -F, -v OFS="," ' # assign input/output field separator to a comma
NR==FNR { # this block is invoked for the 1st read of the input file
for (i = 1; i <= NF; i++) { # loop over the filelds
if (max[i] == "" || max[i] < $i) max[i] = $i
# update the max values
}
nr = NR; nf = NF # store #records and #fields
next # skip following statements
}
FNR==1 { # this block is invoked just before reading he 1st line for the 2nd read of the input file
printf("%d %d ", nr, nf - 1) # print #records and #fields - 1
max[nf]++ # increment the max value of the last field
for (i = 1; i <= nf; i++) { # print max values
printf("%d%s", max[i], i==nf ? "\n" : " ");
}
}
{ # this block is invoked for the 2nd read
$nf++ # increment the value of the last field
print # print fields as csv
}
' datafile.data datafile.data # read the input file twice
Below is the modified code, where I want to read .names file first and then check whether the last line of that .names has a zero then I want to produce the output.
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE * xfopen(const char *path, const char *mode);
void * xmalloc(size_t s);
void parse_line(const char *buf, int *max, int column_count)
{
for(int i = 0; i < column_count; i++ ){
char *end;
int t = strtol(buf, &end, 10);
if( t > max[i] ){
max[i] = t;
}
if( !((i < column_count - 1 && *end == ',') || (i == column_count - 1 && *end == '\n')) ){
fprintf(stderr, "invalid input '%c' in %s", *end, buf);
exit(1);
}
buf = end + 1;
}
}
int main(int argc, char **argv)
{
char *path1;
char *path = argc > 1 ? argv[1] : "stdin";
sprintf(path, "%s.data", argv[1]);
FILE *in = argc > 1 ? xfopen(path, "r") : stdin;
char buf[1024];
int column_count = 1;
int row_count = 1;
int *max;
/* Read first line to determine number of columns */
if( fgets(buf, sizeof buf, in) == NULL ){
fputs("Input error\n", stderr);
return 1;
}
for( const char *p = buf; *p; p++ ){
if( *p == ',' ){
column_count += 1;
}
}
max = xmalloc(column_count * sizeof *max);
for( int i = 0; i < column_count; i++ ){
max[i] = INT_MIN;
}
parse_line(buf, max, column_count);
while( fgets(buf, sizeof buf, in) != NULL ){
row_count += 1;
parse_line(buf, max, column_count);
}
if( fseek(in, 0L, SEEK_SET) ){
perror(path);
return 1;
}
printf("%d %d ", row_count, column_count - 1);
for( int i = 0; i < column_count - 1; i += 1 ){
printf("%d ", max[i]);
}
printf("%d\n", max[column_count - 1] + 1);
while( fgets(buf, sizeof buf, in) != NULL ){
char *comma = strrchr(buf, ',');
if( comma == NULL ){
fprintf(stderr, "Invalid input\n");
return 1;
}
*comma = '\0';
int k = strtol(comma + 1, NULL, 10);
for(char *p = buf; *p; p++){
if( *p == ',' ) *p = ' ';
}
printf("%s %d\n", buf, k + 1);
}
}
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
*mode == 'r' ? stdin : stdout;
if( fp == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
void *
xmalloc(size_t s)
{
void *rv = malloc(s);
if( rv == NULL ){
perror("malloc");
exit(EXIT_FAILURE);
}
return rv;
}

matching string pattern flat file in C

Just to have a look a name in a list, when match, the value is discounted.
I tried to code, but the matching technique is fail. Like I try to find "John", but it match with "John" and "Johnny", whether the expected match is just "John" (case is not sensitive)
Just want to help my mom's store.
What I want is something like:
I have 3 set of flat file (list1.txt, list2.txt, list3.txt). Each file has its name, for example:
John
Rudy
Barrack Obama
John Travolta
List2.txt contained:
Jeddi Sarah
Mute Sand
List3.txt contained:
Greedy Black
Nevada Blue
The program when executed, ask:
Enter name: Greedy Black
Enter price: 1000
If the name is listed in list1.txt, he gets discount price 10%, list2.txt for 20%, and list3.txt for 30%.
example output:
Enter name: Greedy Black
Enter price: 1000
Greedy Black is found in list3.txt, got discount for 10%
price after discount: 900
But if he does not in any list, he gets normal price, which is 1000.
How could I do that in C?
Thank you for the help...
This Works Fine
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_C 111
char *trim(char *str);
int countlines(const char *filename);
char ** names(const char *filename);
int contains(const char* a)
{
int l1 = countlines("list1.txt");
int l2 = countlines("list2.txt");
int l3 = countlines("list3.txt");
char** c1 = names("list1.txt");
char** c2 = names("list2.txt");
char** c3 = names("list3.txt");
for (int i = 0; i < l1; ++i) {
if (strcmp(a,c1[i])== 0 )
return 1;
}
for (int i = 0; i < l2; ++i) {
if (strcmp(a,c2[i])== 0 )
return 2;
}
for (int i = 0; i < l3; ++i) {
if (strcmp(a,c3[i])== 0 )
return 3;
}
for (int j = 0; j < l1; ++j) {
printf("%s\t%s",a,c1[j]);
}
return 0;
}
int main()
{
char * a = (char * ) malloc(MAX_C);
printf("Enter Name:\n");
scanf("%[^\n]",a);
int p;
printf("Enter Price:\n");
scanf("%d",&p);
int c = contains(a);
if(c)
{
printf("Greedy Black is found in list%d.txt, got discount for 10%%\nprice after discount: %f",c,p-p/10.0);
}
else
{
printf("Greedy Black is found in list%d.txt, got discount for 10%%\nprice Without discount: %f",c,p);
}
}
int countlines(const char *filename) {
// count the number of lines in the file called filename
FILE *fp = fopen(filename, "r");
int ch = 0;
int lines = 0;
if (fp == NULL)
return 0;
lines++;
while ((ch = fgetc(fp)) != EOF) {
if (ch == '\n')
lines++;
}
fclose(fp);
return lines;
}
char ** names(const char *filename)
{
int line = countlines(filename);
char ** arr = (char **)malloc(line * sizeof(char *));
for (int i=0; i<line; i++)
arr[i] = (char *)malloc(MAX_C * sizeof(char));
FILE * fp = fopen(filename, "r");
if (fp == NULL) {
printf("Could not open file %s", filename);
return NULL;
}
for (int i = 0; i < line; ++i) {
if(fgets(arr[i], MAX_C, fp)!=NULL)
{
trim(arr[i]);
}
}
return arr;
}
char *trim(char *str)
{
size_t len = 0;
char *frontp = str;
char *endp = NULL;
if( str == NULL ) { return NULL; }
if( str[0] == '\0' ) { return str; }
len = strlen(str);
endp = str + len;
/* Move the front and back pointers to address the first non-whitespace
* characters from each end.
*/
while( isspace((unsigned char) *frontp) ) { ++frontp; }
if( endp != frontp )
{
while( isspace((unsigned char) *(--endp)) && endp != frontp ) {}
}
if( frontp != str && endp == frontp )
*str = '\0';
else if( str + len - 1 != endp )
*(endp + 1) = '\0';
/* Shift the string so that it starts at str so that if it's dynamically
* allocated, we can still free it on the returned pointer. Note the reuse
* of endp to mean the front of the string buffer now.
*/
endp = str;
if( frontp != str )
{
while( *frontp ) { *endp++ = *frontp++; }
*endp = '\0';
}
return str;
}

Split a file of text at delimiters and separate integers and text in c

I am reading text from an input file in. I have to separate text from scores ie
John Doe 100 95 67 85
jane doe 67 78 99
and then average the numbers. I can separate by the spaces using strtok but how can i tell when i have an integer? i need to split the reading of names and of integers into 2 functions. My code to read it works but i need to stop at the end of each name. I attempted to use numbers converted to strings and using strcmp however it did not work.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void read_reverse_write(FILE * ptr_file, FILE * op);
void write_and_avarage(int * fp, char * op);
//int checker(char *token);
int main(int argc, char** argv) {
FILE *fp;
FILE *op;
//opens quiz and checks and checks to make sure it did
fp = fopen("quiz.txt", "r");
if (fp == NULL) {
printf("Error opening file");
return (-1);
}
//opens op and checks that it did
op = fopen("output.txt", "w");
if (op == NULL) {
printf("Error opening file");
return (-1);
}
// runs read reverse write
read_reverse_write(fp, op);
fclose(fp);
fclose(op);
return (EXIT_SUCCESS);
}
void read_reverse_write(FILE * ptr_file, FILE * op) {
char buf[1000];
char *token;
const char delim[2] = " ";
fgets(buf, 1000, ptr_file);
token = strtok(buf, delim);
while (token != 100) {
fprintf(op, "%s ", token);
token = strtok(NULL, delim);
}
}
/*void write_and_avarage(int * fp, char * op) {
}
int checker(char *token) {
char *arr[102];
char ph[4];
for (int p = 0; p < 100; p++) {
if (p < 10) {
snprintf(ph, 1, "%d", p);
arr[p] = ph;
} else if (p < 99) {
snprintf(ph, 2, "%d", p);
arr[p] = ph;
} else if (p = 100) {
snprintf(ph, 3, "%d", p);
arr[p] = ph;
}
}
for (int z = 0; z < 100; z++) {
if (strcmp(token, arr[z]) == 1) {
return 1;
} else {
z++;
}
return 0;
}
}
*/
You can use the following code to check the whether the string is a number or not.
#include <stdio.h>
#include <string.h>
#define MAX_NUM 9
#define MIN_NUM 0
#define ZERO 0
#define MAX_SIZE 1024
int checkDigit(int num, int len)
{
int divisor = 1, checkVal = 0;
if(len <= 2)
divisor = 10;
else if(len > 2)
{
len = len - 1;
while(len != ZERO)
{
divisor = divisor * 10;
len = len - 1;
}
}
checkVal = num/divisor;
if(checkVal > MIN_NUM && checkVal <= MAX_NUM)
return 1;
else
return 0;
}
void main()
{
char array[MAX_SIZE] = "JOHN DOE 120 DOE HELLO 2323 90909";
char *split_token = NULL;
int status = 2, len = 0, sum = 0, total_digits = 0;
float average = 0;
split_token = strtok(array, " ");
while( split_token != NULL )
{
len = strlen(split_token);
status = checkDigit(atoi(split_token), len);
if (1 == status)
{
sum = sum + atoi(split_token);
total_digits = total_digits + 1;
}
split_token = strtok(NULL, " ");
}
average = (float)sum/total_digits;
printf("Average is : %f\n", average);
}
This code will check whether your string is a number or not and finally calculate the average of all the numbers in the given string.
If you need to read from a file, multiple sets of inputs, use fscanf() and use the complete code logic repeatedly for each line of input.
Hope it helps! Do ask if you need the complete code or any clarification for the code.

Resources