Read a matrix from a file - c

This is my function to read a matrix from a file. In the text file I have on the first line 2 is n and 3 is m and on the next two lines is the matrix.
I don't have erros, but my program "stop working" and I don't know why. Thank you!
In main I have: readmatrix(n,m,a, "text.txt");
int readmatrix(int* n,int *m, int a[*n][*m], char* filename){
FILE *pf;
int i,j;
pf = fopen (filename, "rt");
if (pf == NULL)
return 0;
fscanf (pf, "%d",n);
for (i=0;i<*n;i++)
{
for(j=0;j<*m;j++)
fscanf (pf, "%d", &a[i][j]);
}
fclose (pf);
return 1;
}

If your compiler supports VLAs or you are using C99, then you can do this:
#include <stdio.h>
int readmatrix(size_t rows, size_t cols, int (*a)[cols], const char* filename)
{
FILE *pf;
pf = fopen (filename, "r");
if (pf == NULL)
return 0;
for(size_t i = 0; i < rows; ++i)
{
for(size_t j = 0; j < cols; ++j)
fscanf(pf, "%d", a[i] + j);
}
fclose (pf);
return 1;
}
int main(void)
{
int matrix[2][3];
readmatrix(2, 3, matrix, "file.dat");
for(size_t i = 0; i < 2; ++i)
{
for(size_t j = 0; j < 3; ++j)
printf("%-3d ", matrix[i][j]);
puts("");
}
return 0;
}
file.dat looks like this:
1 2 3
4 5 6
and the output of my program is
$ ./a
1 2 3
4 5 6
Note that this is a basic example, you should always check the return value of
fscanf. If file.dat had one row only, then you would get in trouble. Also
there are not numbers in the file, you would get also undefined values in the
matrix.
I'd advice to read the whole line with fgets and then parse the line using
sscanf or some other function like strtok, then it would be easier to react
to errors in the input file.
edit
A more robust way of reading a file like this would be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int **readmatrix(size_t *rows, size_t *cols, const char *filename)
{
if(rows == NULL || cols == NULL || filename == NULL)
return NULL;
*rows = 0;
*cols = 0;
FILE *fp = fopen(filename, "r");
if(fp == NULL)
{
fprintf(stderr, "could not open %s: %s\n", filename, strerror(errno));
return NULL;
}
int **matrix = NULL, **tmp;
char line[1024];
while(fgets(line, sizeof line, fp))
{
if(*cols == 0)
{
// determine the size of the columns based on
// the first row
char *scan = line;
int dummy;
int offset = 0;
while(sscanf(scan, "%d%n", &dummy, &offset) == 1)
{
scan += offset;
(*cols)++;
}
}
tmp = realloc(matrix, (*rows + 1) * sizeof *matrix);
if(tmp == NULL)
{
fclose(fp);
return matrix; // return all you've parsed so far
}
matrix = tmp;
matrix[*rows] = calloc(*cols, sizeof *matrix[*rows]);
if(matrix[*rows] == NULL)
{
fclose(fp);
if(*rows == 0) // failed in the first row, free everything
{
fclose(fp);
free(matrix);
return NULL;
}
return matrix; // return all you've parsed so far
}
int offset = 0;
char *scan = line;
for(size_t j = 0; j < *cols; ++j)
{
if(sscanf(scan, "%d%n", matrix[*rows] + j, &offset) == 1)
scan += offset;
else
matrix[*rows][j] = 0; // could not read, set cell to 0
}
// incrementing rows
(*rows)++;
}
fclose(fp);
return matrix;
}
int main(void)
{
size_t cols, rows;
int **matrix = readmatrix(&rows, &cols, "file.dat");
if(matrix == NULL)
{
fprintf(stderr, "could not read matrix\n");
return 1;
}
for(size_t i = 0; i < rows; ++i)
{
for(size_t j = 0; j < cols; ++j)
printf("%-3d ", matrix[i][j]);
puts("");
}
// freeing memory
for(size_t i = 0; i < rows; ++i)
free(matrix[i]);
free(matrix);
return 0;
}
Now file.dat looks like this:
1 2 3 4
4 5 6 5
9 8 8 7
5 5 5 5
1 1 1 1
And the output is
1 2 3 4
4 5 6 5
9 8 8 7
5 5 5 5
1 1 1 1
In this example I calculate the number of columns only for the first column and
use that number for all other columns. If the input file has rows with less
columns that the first row, then the missing values are stored with 0. If it has rows with
more columns than the row will be trimmed.
I calculate the number of rows like this:
while(sscanf(scan, "%d%n", &dummy, &offset) == 1)
{
scan += offset;
(*cols)++;
}
First I declare a pointer scan to point to line, so that I can modify the
pointer without losing the original line. The %n in sscanf is not counted in
the number of successfull conversions, this returns the position of scan where
it stopped reading. I used that to loop the sscanf. I explicitly check that
sscanf returns 1 and if that's the case, I increment the number of columns and
I update scan to update to the point where sscanf stoppped reading. This
allows me to continue scanning until the end of the line is reached. I use a
similar technique to parse all the integers.

If you're not afraid of using goto, an easy-to-read, robust way to read a matrix looks like this:
typedef struct Matrix
{
size_t width, height;
double **data;
} Matrix;
Matrix read_matrix(char const *filename)
{
Matrix matrix;
FILE *file;
if ((file = fopen(filename, "rt")) == NULL)
goto error;
if (fscanf(file, "%zu %zu", &matrix.width, &matrix.height) != 2)
goto error_file;
if ((matrix.data = (double **)calloc(matrix.height, sizeof(double *))) == NULL)
goto error_file;
for (size_t y = 0; y < matrix.height; ++y)
if ((matrix.data[y] = (double *)malloc(matrix.width * sizeof(double))) == NULL)
goto error_matrix;
for (size_t y = 0; y < matrix.height; ++y)
for (size_t x = 0; x < matrix.width; ++x)
if (fscanf(file, "%lf", &matrix.data[y][x]) != 1)
goto error_matrix;
fclose(file);
return matrix;
error_matrix:
for (size_t y = 0; y < matrix.height; ++y)
free(matrix.data[y]);
free(matrix.data);
error_file:
fclose(file);
error:
return (Matrix){0, 0, NULL};
}

Related

read and write to file in c - compressing matrix

I'm trying to write a compressed bits matrix to a and the read it back.
The writing works great but the reading keeps failing and I dont understand why.
typedef unsigned char BYTE;
int saveCompressImageToFile(const char *fileName, const int *image, int row, int col)
{
FILE *fp = fopen(fileName, "wb");
if (!fp)
return 0;
if (fwrite(&row, sizeof(int), 1, fp) != 1) {
fclose(fp);
return 0;
}
if (fwrite(&col, sizeof(int), 1, fp) != 1) {
fclose(fp);
return 0;
}
int byteCount = row * col / 8;
if (byteCount * 8 < row * col)
byteCount++;
BYTE *data = (BYTE *)calloc(sizeof(BYTE), byteCount);
int dataPos;
int dataShift;
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
dataPos = (i * col + j) / 8;
dataShift =7 - (i * col + j) % 8;
data[dataPos] |= (*(image + i * col + j)) << dataShift;
}
}
if (fwrite(data, sizeof(BYTE), byteCount, fp) != byteCount) {
fclose(fp);
return 0;
}
return 1;
}
int * getImage_compress(const char * fileName, int * pRow, int * pCol)
{
FILE* fp = fopen(fileName, "rb");
if (!fp)
return NULL;
if (fread(pRow, sizeof(int), 1, fp) != 1)
{
fclose(fp);
return NULL;
}
if (fread(pCol, sizeof(int), 1, fp) != 1)
{
fclose(fp);
return NULL;
}
size_t mat_size = *pRow * (*pCol);
int byteCount = mat_size / 8;
if (byteCount * 8 < mat_size)
byteCount++;
BYTE* data = (BYTE*)malloc(sizeof(BYTE)*byteCount);
if (!data)
{
fclose(fp);
return NULL;
}
if (fread(data, sizeof(BYTE), byteCount, fp) != byteCount)
{
free(data);
fclose(fp);
return NULL;
}
fclose(fp);
int* mat = (int*)calloc(mat_size, sizeof(int));
if (!mat)
{
free(data);
fclose(fp);
return NULL;
}
for (int i = 0; i < mat_size; i++)
{
for (int j = 0; j < 8; j++)
{
mat[i * 8 + j] = (data[i] >> (7 - j)) & 0x1;
}
}
free(data);
return mat;
}
for some reason the function throws exception in the last line (return mat;) , "Starter.exe has triggered a breakpoint". occurred , what's going on over there? I've tried to debug that code and I can't tell why I can't return this value but I can access the cells in the debugger. any Suggestions?
Putting the comments in an answer:
So much wrong.
You need to fclose(fp) when there isn't an error in error in your first function. Otherwise not all of the data will be written. Or maybe nothing will be written.
fread(&data, ... would try to read the data over the pointer to the allocated space! It should just be fread(data, ...
You are reassembling the bits backwards from how you put them in. Change the reassembly to data[i] >> (7 - j). Or assemble them in the other direction.
sizeof(BYTE) is 1. You mean 8. Use 8 for those.
Your allocation of mat when decompressing can be up to seven ints shorter than what you're writing. Either allocate mat large enough, using byteCount * 8, or only decompress rows * columns ints.

Read a file character by character and pass them to an array in C

I have to parse a matrix from a file which first line characters are the rows and the cols count and the next lines are the matrix values.
The file contains:
3 3
R R B
B G G
G B R
I wrote the following code, but it crashes.
char** readMatrix(FILE *file) {
char *array;
int el = 0;
while (fscanf_s(file, "%s", array) != EOF) {
array[el] = array;
el++;
}
const int n = array[0] - '0', m = array[1] - '0';
char** matrix = malloc(n * sizeof(char*));
for (int i = 0; i < n; i++)
{
matrix[i] = malloc(m * sizeof(char));
}
int k = 2;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
matrix[i][j] = array[k];
++k;
}
}
return matrix;
}
The size of the matrix is different for the different files. How is it possible to declare a char array without knowing the size?
First you need to check if your FILE is not NULL ( it may crash cause of this )
if ( file == NULL ) {
printf("Error");
exit(1);
}
Then you need to be sure that your FILE's pointer is pointing at the start of the file :
fseek(file, 0, SEEK_SET);
If your rule is : 'The first line always contains two positive integer separate by a space and ending the line just after the second uint', then you can read them like this :
int dim_x = 0, dim_y = 0 ;
fscanf(file, "%d %d\n", &dim_x, &dim_y);
if(dim_x <= 0 || dim_y <= 0){
printf("Impossible to get correct the correct dimensions");
exit(1);
}
Then you can read your file line by line to have the correct data.
There is many variation to read your file. Assuming that any datas of your file are single characters spaced by 1 space or 1 backline, you can loop like this :
char ** matrix = (char**)malloc(sizeof(char*) * nbr_y);
for(int line = 0 ; line < nbr_y ; line ++){
matrix[line] = (char*)malloc(sizeof(char) * nbr_x);
for(int data_x_index = 0 ; data_x_index < nbr_x ; data_x_index ++){
fscanf(f, "%c", &matrix[line][data_x_index]); //Read and stock the character direclty in the matrix
fseek(f, 1, SEEK_CUR); // Go to the next character to read
}
}
for(int i = 0 ; i < nbr_y ; i ++){
for(int j = 0 ; j < nbr_x ; j ++){
printf("%c ", matrix[i][j]);
}
printf("\n");
}
}
Caution : This version is not checking if the text is well formated and if the dimensions are correct !

Reading from file into 2d Array in C without constant size

I have a text file that have content like this
5 6
01111
11110
01000
01111
11010
11111
And i want to made a function read from this file and create 2d array out of the content.
Two Numbers from the first line is the size of array and the size of sub array.
The result of the function should be array like this
{{0,1,1,1,1}, {1,1,1,1,0},{0,1,0,0,0},{0,1,1,1,1},{1,1,0,1,0},{1,1,1,1,1}}
So how would i be able to do that?
Right now i try to made a function like this but it error
int** createArray(FILE *fp)
{
int xdim;
int ydim;
fscanf(fp, "%d %d", &xdim, &ydim);
int** arr = malloc(ydim * sizeof(*arr));;
for (int y = 0; y < ydim; y++)
{
arr[y] = malloc(xdim * sizeof(**arr));
fscanf(fp, "%d %d %d %d", arr[y]);
}
return arr;
}
Just loop xdim times over arr[y] then and read numbers with fscanf. Note that a space " " in fscanf format specifier ignores all whitespaces - tabs, spaces and newlines - so it can just read it all.
int** arr = malloc(ydim * sizeof(*arr));;
if (arr == NULL) {
abort();
}
for (int y = 0; y < ydim; y++) {
arr[y] = malloc(xdim * sizeof(*arr[y]));
if (arr[y] == NULL) {
abort();
}
for (int i = 0; i < xdim; ++i) {
char c;
if (fscanf(fp, " %c", &c) != 1) {
abort(); // handle error
}
arr[i][j] = c - '0';
}
}
Tested on godbolt.

Code not assigning to 2D array correctly (C)

Ok so I'm reading from a text file that looks like this:
3 4
2 1 1 1
6 2 1 -7
-2 2 1 7
First two number are the number of rows and cols.
Then I read in the matrix and want to assign the values to a 2D array:
This is my code:
#include <stdio.h>
int main( int argc, char *argv[] ) {
FILE *inputFile;
char ele[256];
int rows,cols,i,j;
inputFile = fopen(argv[1], "r" );
if(inputFile == 0) {
printf("Can't open '%s'\n", argv[1]);
return 1;
}
fscanf(inputFile, "%d %d", &rows, &cols);
char *array[rows][cols];
for ( i = 0; i < rows; i++ )
{
for ( j = 0; j < cols; j++ )
{
fscanf(inputFile, "%s", ele);
array[i][j] = ele;
}
}
for ( i = 0; i < rows; i++ )
{
for ( j = 0; j < cols; j++ )
{
printf("array[%d][%d] = %s\n", i,j, array[i][j] );
}
}
return 0;
}
First nested loop reads from text file and assign elements to 2D array.
Second loop prints out all the elements of the 2D array.
Right now, my output prints out all the elements of the 2D array but shows them all as 7 (the last element in the text file).
If I print out "ele" in the first loop, it prints out all the elements in the matrix correctly, its just that they're not going into the 2D array 1 by 1.
Disclaimer: I know I'm reading them as chars even though they're ints. That's intentional.
There were a number of error (small ones). The primary errors were your type mismatches regarding your format strings for both fscaf and printf. You cannot read numeric data with %s and hope it will be numeric. To read a signed-character value, you need %hhd for both fscanf and printf. ele is type char not char*. The same with array. However, fixing those fixed the read and store of numbers from the file.
#include <stdio.h>
int main (int argc, char *argv[])
{
if (argc < 2) {
fprintf (stderr, "error: insufficient input. usage: %s <file>\n", argv[0]);
return 1;
}
FILE *inputFile;
char ele;
int rows, cols, i, j;
inputFile = fopen (argv[1], "r");
if (inputFile == 0) {
printf ("Can't open '%s'\n", argv[1]);
return 1;
}
fscanf (inputFile, "%d %d", &rows, &cols);
char array[rows][cols];
for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
fscanf (inputFile, "%hhd", &ele);
array[i][j] = ele;
}
}
for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
printf ("array[%d][%d] = %hhd\n", i, j, array[i][j]);
}
}
return 0;
}
Output
$ ./bin/char_array dat/char_array.dat
array[0][0] = 2
array[0][1] = 1
array[0][2] = 1
array[0][3] = 1
array[1][0] = 6
array[1][1] = 2
array[1][2] = 1
array[1][3] = -7
array[2][0] = -2
array[2][1] = 2
array[2][2] = 1
array[2][3] = 7
As it stands, you're assigning every element in array (each of which is a pointer-to-char) the address of ele[0], which is why they're all printing out as the last string you read into ele. They're all pointing to the same string.
EDIT: Misunderstood what you were getting at, rephrased my reply. Sorry 'bout that.
Instead of this :
array[i][j] = ele;
do this :
array[i][j] = strdup(ele);
strdup allocates memory so at the end of the program you have to release that memory.
I am assuming you want to keep using string, ie char arrays to store the values.
If this is not a requirement you can have a different solution that does not need strdup.

Parse Text File in C - Skip Lines - Repeated Calculation

I have been spinning my wheels for a while trying to figure this out but have not been able to. Hope you can help!
I am currently working on a program that solves Sudoku. The current code that I am showing below takes in as input a 9x9 grid of integers (the Sudoku puzzle) and then generates a solution. This is working fine.
#include <stdio.h>
int isAvailable(int puzzle[][9], int row, int col, int num)
{
int rowStart = (row/3) * 3;
int colStart = (col/3) * 3;
int i, j;
for(i=0; i<9; ++i)
{
if (puzzle[row][i] == num) return 0;
if (puzzle[i][col] == num) return 0;
if (puzzle[rowStart + (i%3)][colStart + (i/3)] == num) return 0;
}
return 1;
}
int fillSudoku(int puzzle[][9], int row, int col)
{
int i;
if(row<9 && col<9)
{
if(puzzle[row][col] != 0)
{
if((col+1)<9) return fillSudoku(puzzle, row, col+1);
else if((row+1)<9) return fillSudoku(puzzle, row+1, 0);
else return 1;
}
else
{
for(i=0; i<9; ++i)
{
if(isAvailable(puzzle, row, col, i+1))
{
puzzle[row][col] = i+1;
if((col+1)<9)
{
if(fillSudoku(puzzle, row, col +1)) return 1;
else puzzle[row][col] = 0;
}
else if((row+1)<9)
{
if(fillSudoku(puzzle, row+1, 0)) return 1;
else puzzle[row][col] = 0;
}
else return 1;
}
}
}
return 0;
}
else return 1;
}
int main()
{
int i, j;
int row,column;
int puzzle[9][9];
//printf("Enter your input:\n");
for (row=0; row <9; row++){
for(column = 0; column <9; column ++){
scanf("%d",&puzzle[row][column]);
}
}
//PRINT INPUT PUZZLE
printf("Original Puzzle:");
printf("\n+-----+-----+-----+\n");
for(i=1; i<10; ++i)
{
for(j=1; j<10; ++j) printf("|%d", puzzle[i-1][j-1]);
printf("|\n");
if (i%3 == 0) printf("+-----+-----+-----+\n");
}
printf("\n");
//PRINT OUTPUT PUZZLE
printf("Solved Puzzle:");
if(fillSudoku(puzzle, 0, 0))
{
printf("\n+-----+-----+-----+\n");
for(i=1; i<10; ++i)
{
for(j=1; j<10; ++j) printf("|%d", puzzle[i-1][j-1]);
printf("|\n");
if (i%3 == 0) printf("+-----+-----+-----+\n");
}
printf("\n");
}
else printf("\n\nNO SOLUTION\n\n");
return 0;
}
I now want to use a text file from Project Euler (https://projecteuler.net/project/resources/p096_sudoku.txt) and have my program generate all 50 of these solutions. The text file has the following format:
Grid 01
003020600
900305001
001806400
008102900
700000008
006708200
002609500
800203009
005010300
Grid 02
200080300
060070084
030500209
000105408
000000000
402706000
301007040
720040060
004010003
...
and so on for 50 total grids.
My question is: What is the best way to parse through this file to
Skip over the "Grid ##" line
Read in the next 9 lines for input
Continue on through the file to repeat the program until the end of the file
EDIT:
Between steps 2 & 3, this is what would happen:
After I read in 9 lines of numbers, I'll use that as input to the program and have the program run and generate a solution, and then look back to the input file and get the next set of numbers and run another iteration of the program.
Thank you for any input and guidance you can provide me!
-Colton
When data in a text file is line formatted, strongly recommend using fgets().
Consider each group of 10 lines as a record. They belong together, if 1 part is in error, the whole group is invalid.
// return 0 on success, -1 on EOF and 1 on format failure
int ReadPuzzle(FILE *inf, int puzzle[][9], int *Grid) {
char buffer[20]; // About 2x expected need
if (fgets(buffer, sizeof buffer, inf) == NULL)
return -1; // File EOF or IO error occurred.
if (sscanf(buffer, "Grid %d", Grid) != 1)
return 1;
for (int row = 0; row < 9; row++) {
if (fgets(buffer, sizeof buffer, inf) == NULL)
return 1; // If Grid line exists, 9 lines _should_ follow
char *p = buffer;
for (int col = 0; col < 9; col++) {
// Use %1d to limit scanning to 1 digit
if (sscanf(p, "%1d", &puzzle[row][col]) != 1)
return 1;
p++;
}
}
return 0;
}
Checks could be added to insure extra data is not on the lines.
You probably want to do some stuff between steps 2 & 3, but what you outline sounds reasonable.

Categories

Resources