问题
So, I have a file that contains a matrix of NxM size. For example:
P2
3 3 1
1 0 0
0 1 0
0 0 1
The 'P2' is just an useless indicator, the first '3' indicates how many columns are and the second '3' indicates how many lines, '1' indicates the maximum value among the matrix's numbers. This matrix was stored in a data structure like this:
typedef struct {
int c; // columns
int l; // lines
unsigned char max; // max value
unsigned char** data // variable to store matrix's numbers
} Matrix;
To store the numbers from file to the data variable, I used the fread function, like this:
Matrix* newMatrix = NULL;
newMatrix = malloc(sizeof(Matrix));
FILE* fp = NULL;
fp = fopen(matrixfile, "r");
long size;
fseek(matrixfile, 0, SEEK_END);
size = ftell(matrixfile);
newMatrix->data = malloc(size);
// Jump the 'P2' bytes.
fseek(matrixfile, 2, SEEK_SET);
// Get the c, l and max values.
fscanf(matrixfile, "%i %i %i", &newMatrix->c, &newMatrix->l, &newMatrix->max);
// Jump a '\n' character.
fseek(matrixfile, 1, SEEK_CUR);
// Get matrix's numbers.
fread(newMatrix->data, 1, size, matrixfile);
Ok, I have the matrix's numbers stored as a string in the 'unsigned char** data' variable. But now I need to work with those numbers, so I'm trying to transform this string into a matrix of integers. I tried to do something like this:
void StringtoInt (Matrix* str){
int matrixAux[str->l][str->c], i, j;
for(i=0; i<str->l; i++)
for(j=0; j<str->c; j++)
sscanf(str->data, "%i ", &matrixAux[i][j]);
}
Well, I understand why this doesn't work and why my 'matrixAux' will be a CxL matrix with only 1's. But I cannot think of any way to work with sscanf without knowing how many elements are in the matrix.
So, my question: is there a better way to transform the 'unsigned char** data' string into a integer matrix WITHOUT changing the 'data' type (unsigned char**)?
I think maybe I'm just using the wrong method to store the file's matrix into the data variable (fread function), or messing up with the pointer to pointer syntax. But I also don't see any other good alternative to do that.
回答1:
Problem 1: Computing the size of data
If the matrix is stored as a text file, just like you have posted, using
fseek(matrixfile, 0, SEEK_END);
size = ftell(matrixfile);
to come up with the size of data
is not correct.
All you have to do is read the number of rows and the number of columns and then, you can use numRows * numCols
to come up with the size of data
.
Problem 2: Allocating memory for data
Use of
newMatrix->data = malloc(size);
to allocate memory for data
seems to indicate a lack of understanding of how memory is allocated.
Type of data
is char**
.
malloc(size)
allocates memory for an array of characters of size size
. Assigning the return value of malloc(size)
to newMatrix->data
is wrong.
What you need is:
newMatrix->data = malloc(numRows*sizeof(char*)); // Assuming you read numRows first.
for ( int i = 0; < numRows; ++i )
{
newMatrix->data[i] = malloc(numCols);
}
Reading the data
Now you can read the data from the file using:
for ( int i = 0; < numRows; ++i )
{
for ( int j = 0; j < numCols; ++j )
{
int number;
if ( fscanf(matrixfile, "%d", &number) == 1 )
{
// Check that number is within range.
// ...
newMatrix->data[i][j] = number;
}
else
{
// Unable to read the number.
// Deal with the error.
exit(1);
}
}
}
回答2:
To scan a number directly into a unsigned char
, use "hhu"
("hh"
available since C99)
sscanf(str->data, "%hhu", &matrixAux[i][j]);
As a text file fseek(matrixfile, 2, SEEK_SET);
is UB. Can only seek to the start, beginning or to a previous tell()
offset. Instead, seek to beginning and fscanf(matrixfile, "P2 %i %i %i", &newMatrix->c, &newMatrix->l, &newMatrix->max);
. Always check fscanf()
results.
来源:https://stackoverflow.com/questions/32958291/sscanf-usage-on-matrix-of-unknown-size