So I'm trying to parsing some data given in a text file into a C program. The text file consists of:
4 4
1 1 0 0
1 1 0 0
0 0 1 1
0 0 1 1
The first two numbers are the row and length needed for the 2D array to store the integers. So far my code is:
file = fopen(argv[1], "r");
if (file == NULL)
{
perror("File IO error\n");
}
else
{
while(fgets(line, sizeof(line), file) != NULL)
{
if(sscanf(line, "%d %d %d %d", &a, &b, &c, &d) == 4)
{
printf("%d %d %d %d\n", a, b, c, d);
}
else
{
sscanf(line, "%d %d", &ROW, &COL);
printf("ROW: %d COL: %d\n", ROW, COL);
}
My problem I'm having is that there are other text files that need to be inputted. They are not the same rows and colums as the above one. E.g:
15 15
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 0 0 1 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 0 0 1 1 1 0 0 0 1 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 0 0 1 1 1 0 0 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 0 0 1 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
As my code is only for 4 integers each line, it wouldn't work on a larger or smaller file. How would I make it dynamic and parse according to the size. Thanks
CodePudding user response:
if your text file is formatted. you can use strtok
and strtol
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
int main() {
char payload[] = {"1 2 3 4"};
char *token = strtok(payload, " ");
while (token) {
int v = (int)strtol(token,NULL,10);
printf("%d\n",v);
token = strtok(NULL, " ");
}
return 0;
}
CodePudding user response:
You can just run scanf in loop like this:
int rows, cols;
if(fscanf(file, "%d %d", &rows, &cols) != 2) {
// error
}
int num;
for(int i = 0; i<rows; i) {
for(int j = 0; j < (cols - 1); j) {
if(fscanf(file, "%d", &num) == 1) {
printf("%d ", num);
}
else { /* error */ }
}
if(fscanf(file, "%d", &num) == 1) {
printf("%d\n", num); // last col handled differently
}
else { /* error */ }
}
If you want to receive whole row at one, you can just use int array (no need for string, like in your example)
int* row = malloc(sizeof(int) * cols); // allocate memory for array
for(int i = 0; i<rows; i) {
for(int j = 0; j < cols; j) {
if(fscanf(file, "%d", &row[j]) != 1) { /* error */}
}
// do what you want with your row
}
free(row); // release array memory
CodePudding user response:
In order to read files with different number of rows and columns, I suggest that you allocate memory dynamically after having read the first line containing the number of rows and columns.
Example:
#include <stdio.h>
#include <stdlib.h> // malloc/free
int main(int argc, char* argv[]) {
if(argc != 2) return 1;
FILE *file = fopen(argv[1], "r");
if (file == NULL) {
perror("fopen");
return 1;
}
int ROW, COL;
if(fscanf(file, "%d %d", &ROW, &COL) != 2 || ROW < 1 || COL < 1) {
fprintf(stderr, "invalid file format\n");
return 1;
}
// allocate the needed memory to store the data:
int (*arr)[COL] = malloc(ROW * sizeof *arr);
if(arr == NULL) {
perror("malloc");
return 1;
}
// read the data from file into your dynamically allocated array:
for(int row = 0; row < ROW; row) {
for(int col = 0; col < COL; col) {
if(fscanf(file, " %d", &arr[row][col]) != 1) {
fprintf(stderr, "invalid file format\n");
fclose(file);
free(arr);
return 1;
}
}
}
fclose(file);
// display the result:
printf("ROW: %d COL: %d\n", ROW, COL);
for(int row = 0; row < ROW; row) {
for(int col = 0; col < COL; col) {
printf("%d ", arr[row][col]);
}
putchar('\n');
}
free(arr); // release the memory allocated dynamically
}