Making a 2d array from a text file - c

Im working with a sparse matrix and im given a text file like this:
0 3 1.2
2 5 3.2
3 0 2.1
3 5 4.2
4 5 2.2
0 0 5.2
Basically the way it works is the number 1.2 goes on the position [0] [3] and the elements of the matriz that are not mentioned stay at 0, so in this case it should look like this:
5.2 0 0 1.2 0 0
0 0 0 0 0 0
0 0 0 0 0 3.2
2.1 0 0 0 0 4.2
0 0 0 0 0 2.2

OP wrote this in the comments:
Im so sorry but my teacher clarified everything just now... it turns out that, for each line, the first number is the row, the second the column and the third the element.with the example i have above, 1.2 has to go in the position [0][3]. The matrix does not have to be square.
This makes every thing different. If you don't know the dimensions of the
matrix, then you have to read everything first, then calculate the matrix
dimensions, allocate space for the matrix and then fill it with the values.
I'd do this:
#include <stdio.h>
#include <stdlib.h>
#define BLOCK 1024
struct matrix_info {
int col;
int row;
double val;
};
void free_matrix(double **matrix, size_t rows)
{
if(matrix == NULL)
return;
for(size_t i = 0; i < rows; ++i)
free(matrix[i]);
free(matrix);
}
double **readmatrix(const char *fname, size_t *rows, size_t *cols)
{
if(fname == NULL || rows == NULL || cols == NULL)
return NULL;
double **matrix = NULL;
struct matrix_info *info = NULL;
size_t mi_idx = 0; // matrix info index
size_t mi_size = 0;
FILE *fp = fopen(fname, "r");
if(fp == NULL)
{
fprintf(stderr, "Cannot open %s\n", fname);
return NULL;
}
*rows = 0;
*cols = 0;
for(;;)
{
if(mi_idx >= mi_size)
{
struct matrix_info *tmp = realloc(info, (mi_size + BLOCK) * sizeof *info);
if(tmp == NULL)
{
fprintf(stderr, "not enough memory\n");
free(info);
fclose(fp);
return NULL;
}
info = tmp;
mi_size += BLOCK;
}
int ret = fscanf(fp, "%d %d %lf", &info[mi_idx].row, &info[mi_idx].col,
&info[mi_idx].val);
if(ret == EOF)
break; // end of file reached
if(ret != 3)
{
fprintf(stderr, "Error parsing matrix\n");
free(info);
fclose(fp);
return NULL;
}
if(*rows < info[mi_idx].row)
*rows = info[mi_idx].row;
if(*cols < info[mi_idx].col)
*cols = info[mi_idx].col;
mi_idx++;
}
fclose(fp);
// mi_idx is now the length of info
// *cols and *rows have the largest index
// for the matrix, hence the dimension is (rows + 1) x (cols + 1)
(*cols)++;
(*rows)++;
// allocating memory
matrix = calloc(*rows, sizeof *matrix);
if(matrix == NULL)
{
fprintf(stderr, "Not enough memory\n");
free(info);
return NULL;
}
for(size_t i = 0; i < *rows; ++i)
{
matrix[i] = calloc(*cols, sizeof **matrix);
if(matrix[i] == NULL)
{
fprintf(stderr, "Not enough memory\n");
free(info);
free_matrix(matrix, *rows);
return NULL;
}
}
// populating matrix
for(size_t i = 0; i < mi_idx; ++i)
{
int r,c;
r = info[i].row;
c = info[i].col;
matrix[r][c] = info[i].val;
}
free(info);
return matrix;
}
int main(void)
{
const char *fn = "/tmp/matrix.txt";
size_t rows, cols;
double **matrix = readmatrix(fn, &rows, &cols);
if(matrix == NULL)
return 1;
for(size_t i = 0; i < rows; ++i)
{
for(size_t j = 0; j < cols; ++j)
printf("%0.3f ", matrix[i][j]);
puts("");
}
free_matrix(matrix, rows);
return 0;
}
The output is (for a file with your sample data)
5.200 0.000 0.000 1.200 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 3.200
2.100 0.000 0.000 0.000 0.000 4.200
0.000 0.000 0.000 0.000 0.000 2.200
So a quick explanation of what I'm doing:
I read the file and store in an dynamically allocated array the information
about the column, the row and the value. This information is stored in the
struct matrix_info *info.
The idea is that I read every line and extract the three values. While I read
the file, I also store the largest index for the column and the row
...
if(*rows < info[mi_idx].row)
*rows = info[mi_idx].row;
if(*cols < info[mi_idx].col)
*cols = info[mi_idx].col;
...
so when the file is read, I know the dimensions of the matrix. Now all values
with their row & column are stored in the info array, so the next step is to
allocate memory for the matrix and fill the values based based on the info[i]
entries.
for(size_t i = 0; i < mi_idx; ++i)
{
int r,c;
r = info[i].row;
c = info[i].col;
matrix[r][c] = info[i].val;
}
At the end I free the memory for info and return the matrix.
Another interesting part is this:
if(mi_idx >= mi_size)
{
struct matrix_info *tmp = realloc(info, (mi_size + BLOCK) * sizeof *info);
if(tmp == NULL)
{
fprintf(stderr, "not enough memory\n");
free(info);
fclose(fp);
return NULL;
}
info = tmp;
mi_size += BLOCK;
}
Because you mentioned that the only thing you know about the matrix is that it
might contain up to 10000 elements, then the input file might be very big.
Instead of reallocating memory for the info elements on every loop, I allocate
chunks of 1024 (BLOCK) info elements at a time. Thus once a block is full,
the next block is allocated and so on. So I call realloc only every 1024
iterations.

you need use in first :
float* sparseMatrix = malloc(sizeof(float) * 10000);
You start read the file and after the first line read you know the nomber of colums and the number of row is the number of line read. After you can reduce the matrix if you want.
free(sparseMatrix );
sparseMatrix = malloc(sizeof(float) * nbRow*nbColum);

You simply don't have enough information to construct an appropriate matrix. In your cited case, you know you have AT LEAST 5 rows and AT LEAST 6 columns, but you don't know exactly how many rows m and columns n are in your matrix. So for your given input:
0 3 1.2
2 5 3.2
3 0 2.1
3 5 4.2
4 5 2.2
0 0 5.2
You could have a 5x6 matrix as:
5.2 0.0 0.0 1.2 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 3.2
2.1 0.0 0.0 0.0 0.0 4.2
0.0 0.0 0.0 0.0 0.0 2.2
Or you could have a 10x6 matrix as:
5.2 0.0 0.0 1.2 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 3.2
2.1 0.0 0.0 0.0 0.0 4.2
0.0 0.0 0.0 0.0 0.0 2.2
0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0
This ambiguity is a problem as the first matrix is vastly different that the second.
Also, the point of a sparse matrix is to be efficient with memory and/or processing time. If you allocate a full array of m rows and n columns then you have a dense matrix representation instead.

There's no real way of knowing what's in a file unless you completely read the file yourself first.
Since you know that there will be max 10k elements, you can statically allocate an array of that size first, and then load the numbers into the until you parse an EOF.
float sparseMatrix[10000];
It just means that your program will always allocate the space for 10k elements regardless of how many elements are actually in the array. If you assume that each element takes up 4 bytes, then you'll only be using ~40kB of memory. This is probably the easiest solution.
The other option would be to read the file fully, figure out the required size, and dynamically allocate that size, then read through the whole file again whilst populating the elements.
// Assume numberOfElements was determined by reading through the file first
float* sparseMatrix = malloc(sizeof(float) * numberOfElements);
Though this method will use less memory, it requires two full reads of the file + the overhead of calling malloc.

You can measure the number of rows and columns and then define your 2d array. Of course, this will increase the time complexity! If you don't care about the size of the memory, you can define your array with the max columns and rows! So you should choose between big time complexity and big memory size.

Related

How should I make this logic in C?

There is this linear system given by the following 2d array:
1.0 0.0 -1.0 -4.9 -5.9 -6.9 -7.9
0.0 1.0 2.0 4.4 5.4 6.4 7.4
0.0 0.0 0.0 5.7 5.7 -3.3 -3.3
0.0 0.0 0.0 2.9 2.9 2.9 2.9
0.0 0.0 0.0 7.0 -1.0 -3.0 -3.0
0.0 0.0 -20.0 -65.9 -89.9 -100.9 128.9
Whenever I get a 0 in my main diagonal (when row equals column), I want to change the order of the rows, so there's no zeroes on my main diagonal.
In this case, the row 2(counting from 0) should be traded with row 5 (also counting from 0) because with this, there is no 0s on the main diagonal.
I'm already doing that, but I'm "deleting" the first line and appending it on the end of the linear system. How should I make this logic to know where to exactly trade the rows?
The code is as follows:
void change_order(double linear[6][7], unsigned int qty) {
double aux[100];
// dynamically create an array of pointers of size `m`
double **matrix = (double **)malloc((qty + 1) * sizeof(double *));
// dynamically allocate memory of size `n` for each row
for (int r = 0; r < qty+ 1; r++) {
matrix[r] = (double *)malloc((qty + 1) * sizeof(double));
}
for (int i = 0; i < qty; i++) {
for (int j = 0; j < qty+ 1; j++) {
if (i == 0)
aux[j] = linear[i][j];
}
}
for (int i = 0; i < qty; i++) {
for (int j = 0; j < qty+ 1; j++) {
matrix[i][j] = linear[i][j];
}
}
remove_line(matrix, 0, qty);
for (int i = 0; i < qty; i++) {
for (int j = 0; j < qty+ 1; j++) {
linear[i][j] = matrix[i][j];
}
}
for (int i = 0; i < qty; i++) {
for (int j = 0; j < qty+ 1; j++) {
if (i == qty- 1) {
linear[i][j] = aux[j];
}
}
}
}
void remove_line(double ** linear, int row, unsigned int qty) {
qty--;
free(linear[row]);
while (row < qty) {
linear[row] = linear[row + 1];
row++;
}
}
int main() {
double matrix[][7] = {
{1.0, 0.0, -1.0, -4.9, -5.9, -6.9, -7.9},
{0.0, 1.0, 2.0, 4.4, 5.4, 6.4, 7.4},
{0.0 , 0.0, 0.0, 5.7, 5.7, -3.3, -3.3},
{0.0 , 0.0, 0.0, 2.9, 2.9, 2.9, 2.9},
{0.0 , 0.0, 0.0, 7.0, -1.0, -3.0, -3.0},
{0.0 , 0.0, -20.0, -65.9, -89.9, -100.9, 128.9}
};
change_order(matrix, 6);
}
Example input:
0 3 2 28
4 0 2 24
2 3 0 16
4 2 1 0
Can be exchanged for:
4 0 2 24
2 3 0 16
4 2 1 0
0 3 2 28
If I'm understanding your requirements correctly, would you please try the following:
#include <stdio.h>
#include <stdlib.h>
#define ROWS 6
#define COLS 7
/*
* search for a trade line to be swapped below the n'th row
*/
int search_trade(double matrix[][COLS], int qty, int n)
{
for (int i = n + 1; i < qty; i++) {
if (matrix[i][n] != 0.0) {
return i; // i'th row is a nice trade
}
}
return -1; // not found
}
/*
* swap m'th row and n'th row
*/
void swap(double matrix[][COLS], int qty, int m, int n)
{
int j;
double tmp;
for (j = 0; j < qty + 1; j++) {
tmp = matrix[m][j];
matrix[m][j] = matrix[n][j];
matrix[n][j] = tmp;
}
}
void change_order(double linear[][COLS], int qty) {
for (int i = 0; i < qty; i++) {
if (linear[i][i] == 0.0) { // found 0 in the diagonal
int k = search_trade(linear, qty, i); // search for the trade row
if (k < 0) { // no applicable trade
fprintf(stderr, "cannot find the row to swap. abort.\n");
exit(1);
} else {
swap(linear, qty, i, k); // swap i'th row and k'th row
}
}
}
}
/*
* print the elements of the matrix
*/
void matprint(double matrix[][COLS], int qty)
{
for (int i = 0; i < qty; i++) {
for (int j = 0; j < qty + 1; j++) {
printf("%.2f%s", matrix[i][j], j == qty ? "\n" : " ");
}
}
printf("\n");
}
int main() {
double matrix[][COLS] = {
{1.0, 0.0, -1.0, -4.9, -5.9, -6.9, -7.9},
{0.0, 1.0, 2.0, 4.4, 5.4, 6.4, 7.4},
{0.0 , 0.0, 0.0, 5.7, 5.7, -3.3, -3.3},
{0.0 , 0.0, 0.0, 2.9, 2.9, 2.9, 2.9},
{0.0 , 0.0, 0.0, 7.0, -1.0, -3.0, -3.0},
{0.0 , 0.0, -20.0, -65.9, -89.9, -100.9, 128.9}
};
matprint(matrix, ROWS);
change_order(matrix, ROWS);
matprint(matrix, ROWS);
}
Output:
0.00 1.00 2.00 4.40 5.40 6.40 7.40
0.00 0.00 0.00 5.70 5.70 -3.30 -3.30
0.00 0.00 0.00 2.90 2.90 2.90 2.90
0.00 0.00 0.00 7.00 -1.00 -3.00 -3.00
0.00 0.00 -20.00 -65.90 -89.90 -100.90 128.90
1.00 0.00 -1.00 -4.90 -5.90 -6.90 -7.90
0.00 1.00 2.00 4.40 5.40 6.40 7.40
0.00 0.00 -20.00 -65.90 -89.90 -100.90 128.90
0.00 0.00 0.00 2.90 2.90 2.90 2.90
0.00 0.00 0.00 7.00 -1.00 -3.00 -3.00
0.00 0.00 0.00 5.70 5.70 -3.30 -3.30
You'll see the 2nd row and the 5th row are swapped.
The main concept is:
Seek the diagonal elements for value 0.
If 0 is found, search for a trade row which has a non-zero value in the same column.
If no trade rows are found, the program prints an error message and aborts.
If a trade row is found, swap the rows.
[Edit]
Answering your comment, the code assumes the count of cols == count of rows + 1.
As your provided example has 4x4 matrix, let me add an extra column as:
double matrix[][COLS] = {
{0, 3, 2, 28, -1},
{4, 0, 2, 24, -1},
{2, 3, 0, 16, -1},
{4, 2, 1, 0, -1}
};
(Please note the value -1 is a dummy value and meaningless so far.)
And modify the #define lines as:
#define ROWS 4
#define COLS 5
Then the program will output:
0.00 3.00 2.00 28.00 -1.00
4.00 0.00 2.00 24.00 -1.00
2.00 3.00 0.00 16.00 -1.00
4.00 2.00 1.00 0.00 -1.00
4.00 0.00 2.00 24.00 -1.00
0.00 3.00 2.00 28.00 -1.00
4.00 2.00 1.00 0.00 -1.00
2.00 3.00 0.00 16.00 -1.00
which shows the rows are properly rearranged having no 0 values in the diagonal.
(BTW your expected result breaks having 0 in the diagonal in the last row.)
**You can make a main function like as follows:
//after passing the linear function
int i,j, temp; // declare i and j as global variables**
for(i=0,i<qty+1,i++)
{
for (j=0;j<qty+1;j++)
{
if(i==j & matrix[i][j]==0)
{
remove_line;
temp = i;
break;
}
}
} // here we are looking for a zero in the diagonal.
for (;i<qty+1;i++)
{
if(matrix[i][j]!=0)
{
matrix[temp][j] = linear[i][j]
}
}
// **here we are increasing the rows till we get a non zero element and then
interchanging the values.**

trying to find the maximum difference between two arrays

edit: Apparently the variabledmaxdoesn't update with every loop.
I have 2 files that are scanned and inputted into 2 separate arrays but when I run the code to find the daily maximum difference between the same elements of the 2 arrays, the output reaches 107374208.000000. Here is my code down below.
void diff()
{
float ftemp[size], mtemp[size], diff[size], count = 1.0;
feb = fopen("feb.txt", "r");
mar = fopen("mar.txt", "r");
for(i = 1; i < size; i++)
{
fscanf(feb, "%f", &ftemp[i]);
fscanf(mar, "%f", &mtemp[i]);
dmax = (i * 3) - 3;
if((mtemp[dmax] - ftemp[dmax]) > count && (mtemp[dmax] - ftemp[dmax]) > 0)
{
count = mtemp[dmax] - ftemp[dmax];
}
}
printf("The highest temperature difference between March and February is %f.\n", count);
}
this is the daily temperatures for February
maximum minimum average
31.6 22.4 25.9
30.2 22.7 25.5
31.2 22.9 26.1
31.3 23.4 26.4
30.7 23.2 26.2
31.3 23.1 26.4
31.6 23.9 26.4
31.6 24.0 26.9
32.7 24.7 27.5
33.8 24.8 27.7
32.4 25.0 27.6
32.1 24.9 27.6
32.7 25.4 27.9
31.9 25.5 27.6
31.9 25.4 27.8
32.1 25.3 27.8
31.7 25.6 27.8
32.6 25.2 27.7
32.2 24.9 27.5
32.2 24.9 27.7
31.7 25.8 27.7
32.3 25.5 27.9
32.1 24.4 27.3
31.5 24.6 27.2
31.8 24.0 27.0
32.0 24.4 27.4
32.4 24.9 27.8
32.1 25.0 27.6
and this is the daily temperatures of March
maximum minimum average
32.7 25.1 27.7
33.8 24.8 28.0
32.9 24.7 27.6
32.9 25.0 27.8
32.9 25.0 27.8
33.0 23.8 27.5
32.6 24.2 27.6
32.8 24.8 27.9
32.0 24.2 27.6
32.3 24.9 27.8
33.6 25.0 28.1
33.4 25.6 28.3
33.8 24.7 28.3
34.1 25.2 28.6
32.7 25.9 28.6
28.2 23.6 25.9
30.7 24.3 26.4
32.7 24.9 27.5
32.5 25.4 27.5
33.6 25.9 27.6
33.1 25.3 27.7
31.0 25.0 27.5
32.8 24.2 27.9
33.0 24.7 28.1
33.2 25.2 28.4
34.0 25.7 28.8
34.4 25.8 29.1
32.7 26.2 28.6
33.3 26.5 28.5
32.3 25.8 28.5
33.0 26.6 28.8
The code doesn't compile because there's a bunch of undeclared variables like dmax and ftemp.
After fixing that...
The fopens are unchecked.
The files are assumed to be a certain size.
It's reading well past the initialized portion of the arrays.
fscanf is not checked.
fscanf is a bug generator.
Let's have a look at your loop.
for(i = 1; i < size; i++)
{
fscanf(feb, "%f", &ftemp[i]);
fscanf(mar, "%f", &mtemp[i]);
dmax = (i * 3) - 3;
if((mtemp[dmax] - ftemp[dmax]) > count && (mtemp[dmax] - ftemp[dmax]) > 0)
{
count = mtemp[dmax] - ftemp[dmax];
}
}
After the first iteration, dmax will always be larger than i (i = 0, dmax = 0; i = 1, dmax = 3; i = 2, dmax = 6). But the loop is only ever populated up to i. So mtemp[dmax] and ftemp[dmax] will never be populated when you try to use them. You'll get garbage.
I suspect you're assuming that fscanf(feb, "%f", &ftemp[i]) is scanning in a whole row of numbers. It's only scanning in one, just like you asked for. To do a whole row, you have to ask for that.
for( int i = 0; i < size; i += 3 ) {
fscanf(feb, "%f %f %f", &ftemp[i], &ftemp[i+1], &ftemp[i+2]);
fscanf(mar, "%f %f %f", &mtemp[i], &mtemp[i+1], &mtemp[i+2]);
...
}
Note that the loop starts at 0 because arrays start from 0. And it advances by 3, because we're reading in 3 at a time.
This still doesn't work. The first line of your files are all strings, not floating point numbers. fscanf doesn't skip ahead to find a match, if it doesn't match it stops. If you keep trying the same match it will keep trying to read from the same position over and over and over and over again. All your code is doing is trying to read in the first bytes of each file as a floating point number, failing, and then doing it again size times. ftemp[i] and mtemp[i] remain uninitialized so you get garbage.
This is why scanf and fscanf should be avoided. Instead, read in whole lines and process them with sscanf.
The arrays are also unnecessary, you're not doing anything with the previous values, you just need the current min and max.
Taking that all into account, and a few other things, I've rewritten it like this:
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <stdlib.h>
/* A little function to open files while checking it was
successful and giving a good error message if not */
FILE *open_file( const char *file, const char *mode ) {
FILE *fp = fopen(file, mode);
if( fp == NULL ) {
fprintf(
stderr,
"Could not open '%s' for '%s': %s\n",
file, mode, strerror(errno)
);
exit(1);
}
return fp;
}
/* Instead of using hard coded file names, they're passed in. */
/* Instead of hard coding the use of the diff, it's returned. */
/* I switched to doubles because that's what fabs() returns and
the extra accuracy can't hurt. */
double largest_max_temp_diff(const char *file1, const char* file2) {
FILE *feb = open_file(file1, "r");
FILE *mar = open_file(file2, "r");
char line1[1024];
char line2[1024];
/* Skip the header lines */
fgets(line1, 1024, feb);
fgets(line2, 1024, mar);
double max_diff = 0;
/* Loop infinitely, loop exit is handled using `break` */
while(1) {
/* Read in a line from each file.
Stop when we reach the end of either file. */
if( fgets(line1, 1024, feb) == NULL ) {
break;
}
if( fgets(line2, 1024, mar) == NULL ) {
break;
}
/* Read in just the first column, ignore the rest. */
/* Make sure the parsing was successful. */
double max1, max2;
if( sscanf(line1, "%lf %*lf %*lf", &max1) < 1 ) {
fprintf( stderr, "Could not understand '%s'", line1);
continue;
}
if( sscanf(line2, "%lf %*lf %*lf", &max2) < 1 ) {
fprintf( stderr, "Could not understand '%s'", line2);
continue;
}
/* Compare the diffs as absolute values */
double diff = max2 - max1;
if(fabs(diff) > fabs(max_diff)) {
max_diff = diff;
}
}
/* Return the max diff so it can be used as the caller likes */
return max_diff;
}
int main() {
/* Get the diff */
double diff = largest_max_temp_diff("feb.txt", "mar.txt");
/* Use it */
printf("The highest temperature difference between March and February is %f.\n", diff);
}
This new code now skips the header lines. It reads a line and parses it separately guaranteeing it won't get stuck. It parses one line at a time using sscanf only storing the max. It checks that the parsing succeeded.
It uses the absolute value to check for the maximum difference, because a difference of -4 is bigger than 3.
Finally, it returns that value for the caller to do what it wants with it. Calculating and printing (or any formatting) in the same function is a red flag; it makes functions inflexible and you wind up writing a lot of duplicate code.
It's not the best code, there's still a lot of duplication, but it's better and it checks itself. When working with files, you always have to check your assumptions.

Scanf stops working abruptly

I'm trying to read data from an stl file, one character at a time using scanf/fscanf. I call scanf many times in my program, but input all the data at the first instance. It works perfectly for a while, but it seems like as soon as scanf is called the 1022nd or 1023rd time, the program stops and prompts for more input, even though there is plenty left to scan.
I've written a program before that called scanf more than 40,000 times on one input, so I don't know what the deal is...
It seems to stop working at the first scanf in getnormal() when z == 7;
#include <stdio.h>
#include <stdlib.h>
void getnormal(char[], double[]);
void getvertices(char[], double[], int);
int main (int argc, char *argv[]) {
unsigned char trash = 0;
int z = 0;
char num[20];
for (int i = 0; i < 20; i++)
num[i] = 48;
double normal [3] = {0,0,0};
double vertices [9] = {0,0,0,0,0,0,0,0,0};
//FILE *in = fopen(argv[1], "r");
//FILE *out = fopen(argv[2], "w");
while (trash != '\n')
scanf("%c", &trash);
while (1) {
getnormal(num, normal);
for (int i = 1; i <= 3; i++)
getvertices(num, vertices, i);
z++;
}
}
double getnumber(char num[]) {
unsigned char trash = 0;
for (int i = 0; i < 20; i++)
num[i] = 48;
scanf("%c", &trash);
for (int j = 0; trash != ' ' && trash != '\n'; j++) {
num[j] = trash;
scanf("%c", &trash);
if (trash == 'e') {
for (int h = 0; h < 4; h++)
scanf("%c", &trash);
break;
}
}
return atof(num);
}
void getnormal(char num[], double normal[]) {
unsigned char trash = 0;
while (trash != 'm')
scanf("%c", &trash);
while (trash != 'l')
scanf("%c", &trash);
scanf("%c", &trash);
for (int i = 0; i < 3; i++)
normal[i] = getnumber(num);
printf("\nnormal:");
for (int i = 0; i < 3; i++)
printf(" %f", normal[i]);
printf("\n");
}
void getvertices(char num[], double vertices[], int vertex) {
unsigned char trash = 0;
vertex = (vertex-1) * 3;
while (trash != 'x')
scanf("%c", &trash);
scanf("%c", &trash);
for (int i = 0; i < 3; i++)
vertices[vertex+i] = getnumber(num);
printf("vertex:");
for (int i = 0; i < 3; i++) {
printf(" %f", vertices[vertex+i]);
}
printf("\n");
}
Here's the input:
solid Untitled-56807ca1
facet normal 0.0 0.0 -1.0
outer loop
vertex 100.0 50.0 0.0
vertex 0.0 0.0 0.0
vertex 0.0 50.0 0.0
endloop
endfacet
facet normal 0.0 0.0 -1.0
outer loop
vertex 0.0 0.0 0.0
vertex 100.0 50.0 0.0
vertex 100.0 0.0 0.0
endloop
endfacet
facet normal -1.0 0.0 0.0
outer loop
vertex 0.0 50.0 67.80499999999999
vertex 0.0 0.0 0.0
vertex 0.0 0.0 67.80499999999999
endloop
endfacet
facet normal -1.0 0.0 0.0
outer loop
vertex 0.0 0.0 0.0
vertex 0.0 50.0 67.80499999999999
vertex 0.0 50.0 0.0
endloop
endfacet
facet normal -0.0 1.0 0.0
outer loop
vertex 0.0 50.0 67.80499999999999
vertex 100.0 50.0 0.0
vertex 0.0 50.0 0.0
endloop
endfacet
facet normal -0.0 1.0 0.0
outer loop
vertex 100.0 50.0 0.0
vertex 0.0 50.0 67.80499999999999
vertex 100.0 50.0 67.80499999999999
endloop
endfacet
facet normal 1.0 0.0 0.0
outer loop
vertex 100.0 50.0 0.0
vertex 100.0 0.0 67.80499999999999
vertex 100.0 0.0 0.0
endloop
endfacet
facet normal 1.0 0.0 0.0
outer loop
vertex 100.0 0.0 67.80499999999999
vertex 100.0 50.0 0.0
vertex 100.0 50.0 67.80499999999999
endloop
endfacet
facet normal -0.0 -1.0 -0.0
outer loop
vertex 100.0 0.0 67.80499999999999
vertex 0.0 0.0 0.0
vertex 100.0 0.0 0.0
endloop
endfacet
facet normal -0.0 -1.0 -0.0
outer loop
vertex 0.0 0.0 0.0
vertex 100.0 0.0 67.80499999999999
vertex 0.0 0.0 67.80499999999999
endloop
endfacet
facet normal 0.8393626319551987 8.038371845750061e-18 0.5435718646851044
outer loop
vertex 100.0 50.0 67.80499999999999
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 100.0 0.0 67.80499999999999
endloop
endfacet
facet normal 0.8393626319551987 8.038371845750061e-18 0.5435718646851044
outer loop
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 100.0 50.0 67.80499999999999
vertex 68.99999999999989 34.49999999999993 115.67399999999996
endloop
endfacet
facet normal -0.8393626319552003 -1.4889432537737797e-17 0.5435718646851019
outer loop
vertex 30.9999999999999 15.49999999999995 115.67399999999996
vertex 0.0 50.0 67.80499999999999
vertex 0.0 0.0 67.80499999999999
endloop
endfacet
facet normal -0.8393626319552003 -1.4889432537737797e-17 0.5435718646851019
outer loop
vertex 0.0 50.0 67.80499999999999
vertex 30.9999999999999 15.49999999999995 115.67399999999996
vertex 30.9999999999999 34.49999999999993 115.67399999999996
endloop
endfacet
facet normal -5.5971483140148576e-18 -0.9513689920122365 0.30805363337837904
outer loop
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 0.0 0.0 67.80499999999999
vertex 100.0 0.0 67.80499999999999
endloop
endfacet
facet normal -5.5971483140148576e-18 -0.9513689920122365 0.30805363337837904
outer loop
vertex 0.0 0.0 67.80499999999999
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 30.9999999999999 15.49999999999995 115.67399999999996
endloop
endfacet
facet normal 9.646494768713815e-18 0.9513689920122359 0.30805363337838126
outer loop
vertex 30.9999999999999 34.49999999999993 115.67399999999996
vertex 100.0 50.0 67.80499999999999
vertex 0.0 50.0 67.80499999999999
endloop
endfacet
facet normal 9.646494768713815e-18 0.9513689920122359 0.30805363337838126
outer loop
vertex 100.0 50.0 67.80499999999999
vertex 30.9999999999999 34.49999999999993 115.67399999999996
vertex 68.99999999999989 34.49999999999993 115.67399999999996
endloop
endfacet
facet normal 0.0 -0.8819736246769688 0.47129876445219904
outer loop
vertex 49.99999999999989 24.99999999999994 133.45199999999997
vertex 30.9999999999999 15.49999999999995 115.67399999999996
vertex 68.99999999999989 15.49999999999995 115.67399999999996
endloop
endfacet
facet normal 0.6832351395351168 5.963605871623595e-18 0.7301984278978073
outer loop
vertex 68.99999999999989 34.49999999999993 115.67399999999996
vertex 49.99999999999989 24.99999999999994 133.45199999999997
vertex 68.99999999999989 15.49999999999995 115.67399999999996
endloop
endfacet
facet normal -0.6832351395351168 5.963605871623845e-18 0.7301984278978073
outer loop
vertex 49.99999999999989 24.99999999999994 133.45199999999997
vertex 30.9999999999999 34.49999999999993 115.67399999999996
vertex 30.9999999999999 15.49999999999995 115.67399999999996
endloop
endfacet
facet normal -0.0 -0.0 1.0
outer loop
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 30.9999999999999 34.49999999999993 115.67399999999996
vertex 30.9999999999999 15.49999999999995 115.67399999999996
endloop
endfacet
facet normal -0.0 -0.0 1.0
outer loop
vertex 30.9999999999999 34.49999999999993 115.67399999999996
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 68.99999999999989 34.49999999999993 115.67399999999996
endloop
endfacet
facet normal -0.0 0.8819736246769686 0.47129876445219915
outer loop
vertex 49.99999999999989 24.99999999999994 133.45199999999997
vertex 68.99999999999989 34.49999999999993 115.67399999999996
vertex 30.9999999999999 34.49999999999993 115.67399999999996
endloop
endfacet
endsolid Untitled-56807ca1
Here's the output:
normal: 0.000000 0.000000 -1.000000
vertex: 100.000000 50.000000 0.000000
vertex: 0.000000 0.000000 0.000000
vertex: 0.000000 50.000000 0.000000
normal: 0.000000 0.000000 -1.000000
vertex: 0.000000 0.000000 0.000000
vertex: 100.000000 50.000000 0.000000
vertex: 100.000000 0.000000 0.000000
normal: -1.000000 0.000000 0.000000
vertex: 0.000000 50.000000 67.805000
vertex: 0.000000 0.000000 0.000000
vertex: 0.000000 0.000000 67.805000
normal: -1.000000 0.000000 0.000000
vertex: 0.000000 0.000000 0.000000
vertex: 0.000000 50.000000 67.805000
vertex: 0.000000 50.000000 0.000000
normal: -0.000000 1.000000 0.000000
vertex: 0.000000 50.000000 67.805000
vertex: 100.000000 50.000000 0.000000
vertex: 0.000000 50.000000 0.000000
normal: -0.000000 1.000000 0.000000
vertex: 100.000000 50.000000 0.000000
vertex: 0.000000 50.000000 67.805000
vertex: 100.000000 50.000000 67.805000
normal: 1.000000 0.000000 0.000000
vertex: 100.000000 50.000000 0.000000
vertex: 100.000000 0.000000 67.805000
vertex: 100.000000 0.000000 0.000000
When you get into handling text files containing more than the basic "each line holds the same information", you are better served utilizing line-oriented input functions like fgets or getline in order to separate 'reading' of your data and 'processing (or parsing)' of your data that too often people attempt to shoehorn into a scanf format string that results in more grief than good.
As mentioned in my comment, when all the input lines are guaranteed to hold the same type and number of variables, and in the exact same format on every line, then the scanf family of input functions can be used fairly reliably. But when your data varies line-by-line, reading each line into a buffer and then having the luxury of writing a handler to parse and validate what was read will result in a far more robust code.
Before beginning your reading, you must decide on how you will hold your values in memory. Whether in a struct, an array, a combination? While C is flexible enough to allow you wide latitude in how you store your data, a bit of thinking up-front on what parts of your data are relatively fixed and what parts will continue to grow, can help you sort out a reasonable storage scheme.
In your case, the data you need that is relatively fixed in size is the name (or label) for your solid (e.g. Untitled-56807ca1 in your sample data). The number of normal/vertex sets can be a single number, and keeping track of the max number you can store is also a single number.
The data that will grow as you read from your input file will be the values for the facet normal arrays and the vertex arrays. Here you will need some way of reading as many as are contained in the file (likely without knowing how many are there when you start). Of course, if you do not need to store the data, but simply use the values as they are read, this isn't a concern, but in most cases, you want to be able to store your data so it can be passed to other parts of your code where it can be used.
While you can do it a number of ways, a nested struct, where the fixed values are members of the outer, or base, struct, which also holds a pointer to your data (or nested struct of normal and vertex arrays makes sense. You can make life easier with a simple create or initialization function that allocates and initializes the structs and their values each time a new named solid is read.
After setting up how you will hold/store your data, it is then just a matter of reading each line, examining/parsing the line contents, and taking the appropriate actions based on what you find in each line. You should also make sure you get what you expect to find in each line, and warn or throw an error if your code reads a line it doesn't understand.
There is no better way to put these pieces together than in a short example to read your posted input file so you can get a flavor for it. Note: there are many ways to do this in C, all with their advantages/disadvantages, this is just one for you to consider and to ask questions about to help your understand how a line-oriented approach may benefit what you are attempting to do. Look over the example and let me know what questions you have:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h> /* for ERANGE and errno */
#include <math.h> /* for HUGE_VALF, HUGE_VALL */
/* constants - num dimensions, initial facets
* allocated within each solid, and the max
* chars per-line for fgets to read
*/
enum { NDIM = 3, FACETS = 32, MAXC = 256 };
/* facets struct - declared as pointer member of
* struct solid allowing additional allocation to
* hold as many normal/vertexes as required.
*/
typedef struct {
double normal[NDIM];
double vertex[NDIM][NDIM];
} facet;
/* struct solid holds the solid's name,
* a pointer to an array of stuct facet,
* the number of facets containing data, and
* the maximum presently allocated.
*/
typedef struct {
char *name;
facet *facet;
size_t nfacets;
size_t maxfacets;
} solid;
/* function prototypes */
solid *create_solid ();
solid *read_solid (solid **sol, FILE *fp);
void print_solid (solid *sol);
void free_solid (solid *sol);
double xstrtod (char *str, char **ep);
int main (int argc, char **argv) {
solid *sol = NULL; /* pointer to hold values */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open */
fprintf (stderr, "error: file open failed '%s'\n", argv[1]);
return 1;
}
if (read_solid (&sol, fp)) { /* read data from file */
print_solid (sol); /* print data read */
free_solid (sol); /* free all memory */
}
if (fp != stdin) fclose (fp); /* close if not stdin */
return 0;
}
/* read_solid takes the poiner address for a struct solid,
* and will read all normal and vertexes into the struct,
* updating 'nfacets' with the number of facets for which
* there is data, and will validate each read and conversion
* of values from string to double. retuns filled struct on
* success, NULL otherwise
*/
solid *read_solid (solid **sol, FILE *fp)
{
char line[MAXC] = {0}; /* temporary line buffer */
size_t idx = 0, vidx = 0; /* line & vertex indexes */
if (!*sol) *sol = create_solid(); /* allocate & initialize struct */
while (fgets (line, MAXC, fp)) { /* read each line in file */
size_t len = 0;
char *p, *ep;
p = ep = line;
len = strlen (line); /* get length & remove '\n' */
if (line[len - 1] == '\n') line[--len] = 0;
if (!(ep = strchr (line, ' '))) /* test if space in line */
{ /* if endfacet, update nfacets */
if (strcmp ("endfacet", line) == 0) {
(*sol)->nfacets++;
if ((*sol)->nfacets == (*sol)->maxfacets) {
/* reallocate (*sol)->facets here,
* update (*sol)->maxfacets to new size
*/
fprintf (stderr, "read_solid() warning: limit reached\n"
"you must reallocate or increase FACETS\n");
break;
}
}
goto processed;
}
if (strncmp ("solid", line, ep - p) == 0)
{ /* begins with 'solid', set 'name' */
(*sol)->name = strdup (ep + 1);
goto processed;
}
else if (strncmp ("facet", line, ep - p) == 0)
{ /* read facet normal values */
size_t i;
while (*ep && (*ep < '0' || *ep > '9')) ep++;
if (!*ep) {
fprintf (stderr, "read_solid() error: facet normal no values.\n");
return NULL;
}
p = ep;
for (i = 0; i < NDIM; i++) { /* convert to double & validate */
(*sol)->facet[(*sol)->nfacets].normal[i] = xstrtod (p, &ep);
p = ep;
}
goto processed;
}
else if (strncmp ("vertex", line, ep - p) == 0)
{ /* read vertex values */
size_t i;
p = ep + 1;
for (i = 0; i < NDIM; i++) { /* convert to double & validate */
(*sol)->facet[(*sol)->nfacets].vertex[vidx][i] = xstrtod (p, &ep);
p = ep;
}
vidx = vidx < 2 ? vidx + 1 : 0; /* update/reset vertex index */
goto processed;
}
else if (strncmp ("outer", line, ep - p) == 0) {
goto processed;
}
else if (strncmp ("endsolid", line, ep - p) == 0) {
goto processed;
}
else { /* if any line not processed - warn of unrecognized line */
fprintf (stderr, "read_solid() warning: invalid line at '%zu'\n", idx);
}
processed:
idx++; /* update line index */
}
if (!(*sol)->nfacets) { /* if no facet data, free mem, return NULL */
fprintf (stderr, "read_solid() error: no data read.\n");
free_solid (*sol);
return NULL;
}
return *sol;
}
/* simple allocate/initialize function
* return must be assigned to pointer
*/
solid *create_solid ()
{
size_t i;
solid *sol = calloc (1, sizeof *sol);
sol->facet = calloc (FACETS, sizeof *(sol->facet));
sol->nfacets = 0;
sol->maxfacets = FACETS;
for (i = 0; i < FACETS; i++) {
memset ((sol->facet)[i].normal, 0, NDIM * sizeof (double));
memset ((sol->facet)[i].vertex, 0, NDIM * NDIM * sizeof (double));
}
return sol;
}
/* simple print of normals & vertexes to stdout */
void print_solid (solid *sol)
{
if (!sol) {
fprintf (stderr, "print_solid() error: invalid parameter 'sol'.\n");
return;
}
size_t n, i;
printf ("\nnormal and vertexes for solid: %s\n", sol->name);
for (n = 0; n < sol->nfacets; n++) {
printf ("\n normal[%3zu] : %10.4f %10.4f %10.4f\n", n,
sol->facet[n].normal[0],
sol->facet[n].normal[1],
sol->facet[n].normal[2]);
for (i = 0; i < NDIM; i++)
printf (" vertex[%2zu] : %10.4f %10.4f %10.4f\n", i,
sol->facet[n].vertex[i][0],
sol->facet[n].vertex[i][1],
sol->facet[n].vertex[i][2]);
}
}
/* free allocated memory */
void free_solid (solid *sol)
{
if (sol->name) free (sol->name);
if (sol->facet) free (sol->facet);
if (sol) free (sol);
}
/* string to double with error checking. */
double xstrtod (char *str, char **ep)
{
errno = 0;
double val = strtod (str, ep);
/* Check for various possible errors */
if ((errno == ERANGE && (val == HUGE_VAL || val == HUGE_VALL)) ||
(errno != 0 && val == 0)) {
perror ("strtod");
exit (EXIT_FAILURE);
}
if (ep && *ep == str) {
fprintf (stderr, "No digits were found\n");
exit (EXIT_FAILURE);
}
return val;
}
Compile (gcc)
gcc -Wall -Wextra -O3 -o bin/readsolid readsolid.c
Use/Output
$ ./bin/readsolid dat/solid.txt
normal and vertexes for solid: Untitled-56807ca1
normal[ 0] : 0.0000 0.0000 -1.0000
vertex[ 0] : 100.0000 50.0000 0.0000
vertex[ 1] : 0.0000 0.0000 0.0000
vertex[ 2] : 0.0000 50.0000 0.0000
normal[ 1] : 0.0000 0.0000 -1.0000
vertex[ 0] : 0.0000 0.0000 0.0000
vertex[ 1] : 100.0000 50.0000 0.0000
vertex[ 2] : 100.0000 0.0000 0.0000
normal[ 2] : 1.0000 0.0000 0.0000
vertex[ 0] : 0.0000 50.0000 67.8050
vertex[ 1] : 0.0000 0.0000 0.0000
vertex[ 2] : 0.0000 0.0000 67.8050
normal[ 3] : 1.0000 0.0000 0.0000
vertex[ 0] : 0.0000 0.0000 0.0000
vertex[ 1] : 0.0000 50.0000 67.8050
vertex[ 2] : 0.0000 50.0000 0.0000
normal[ 4] : 0.0000 1.0000 0.0000
vertex[ 0] : 0.0000 50.0000 67.8050
vertex[ 1] : 100.0000 50.0000 0.0000
vertex[ 2] : 0.0000 50.0000 0.0000
<snip>
normal[ 21] : 0.0000 -0.0000 1.0000
vertex[ 0] : 69.0000 15.5000 115.6740
vertex[ 1] : 31.0000 34.5000 115.6740
vertex[ 2] : 31.0000 15.5000 115.6740
normal[ 22] : 0.0000 -0.0000 1.0000
vertex[ 0] : 31.0000 34.5000 115.6740
vertex[ 1] : 69.0000 15.5000 115.6740
vertex[ 2] : 69.0000 34.5000 115.6740
normal[ 23] : 0.0000 0.8820 0.4713
vertex[ 0] : 50.0000 25.0000 133.4520
vertex[ 1] : 69.0000 34.5000 115.6740
vertex[ 2] : 31.0000 34.5000 115.6740
Memory/Error Check
In any code your write that dynamically allocates memory, you have 2 responsibilites regarding any block of memory allocated: (1) always preserves a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory and to confirm that you have freed all the memory you have allocated.
For Linux valgrind is the normal choice. There are so many subtle ways to misuse a block of memory that can cause real problems, there is no excuse not to do it. There are similar memory checkers for every platform. They are all simple to use. Just run your program through it.
$ valgrind ./bin/readsolid dat/solid.txt
==4651== Memcheck, a memory error detector
==4651== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==4651== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==4651== Command: ./bin/readsolid dat/solid.txt
==4651==
normal and vertexes for solid: Untitled-56807ca1
normal[ 0] : 0.0000 0.0000 -1.0000
vertex[ 0] : 100.0000 50.0000 0.0000
vertex[ 1] : 0.0000 0.0000 0.0000
vertex[ 2] : 0.0000 50.0000 0.0000
<snip>
==4651==
==4651== HEAP SUMMARY:
==4651== in use at exit: 0 bytes in 0 blocks
==4651== total heap usage: 4 allocs, 4 frees, 3,690 bytes allocated
==4651==
==4651== All heap blocks were freed -- no leaks are possible
==4651==
==4651== For counts of detected and suppressed errors, rerun with: -v
==4651== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
Note: this example ended up longer than I originally envisioned, but to provide adequate validation for any relatively sophisticated set of data, it will take a little bit of code to get it done correctly. Good luck.
Your function getnumber has several problems:
The buffer num is initialized to all '0' without a null terminator. You patch some bytes into it until you see a space or a linefeed and call atof.
There is no test to prevent buffer overflow, invalid input may well cause that at some point in the input file.
The buffer is not null terminated. atof will stop on the first character that does not match the floating point syntax, but if all positions are digits, it will keep reading past the end of the num array.
The whole code is very cumbersome and the semantics are unclear.
You never test the return value from scanf: upon end of file, the contents of the unsigned char whose address is passed as argument to scanf will be indeterminate, most likely untouched from the previous value... potentially causing buffer overflow in getnumber as well.
There is no way for your program to break from the while (1) loop. Sooner or later, you will reach the end of file and your code will either invoke undefined behavior or get stuck in an infinite loop.
Rewrite your code with getchar() or fgets and properly check for end of file.

Program to print and display identity matrix in C

i am having trouble writing a program that prints a matrix, and then I generate the identity matrix. Here is my ccode below and any help would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int PrintMatrix(int dim, double matrix[dim][dim]);
int main()
int PrintMatrix(int dim, double matrix[dim][dim]) {
int aa, bb;
for (aa = 0; aa <= dim; aa++) {
for (bb = 0; bb <= dim; bb++) {
printf("%lf ", matrix[aa][bb]);
}
printf("\n");
}
}
double TestMatrix[7][7] = {
{1,0,0,0,0,0,0},
{0,1,0,0,0,0,0},
{0,0,1,0,0,0,0},
{0,0,0,1,0,0,0},
{0,0,0,0,1,0,0},
{0,0,0,0,0,1,0},
{0,0,0,0,0,0,1}
};
PrintMatrix(7, TestMatrix);
return 0;
Your code won't compile successfully.
After main there is no opening brace.
You are defining function inside main, which is an issue.
Check for parentheses in whole code.
Fixed the loop controls from <= to <.
Here is the modified code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int PrintMatrix(int dim, double matrix[dim][dim]);
int main()
{
double TestMatrix[7][7] = {
{1,0,0,0,0,0,0},
{0,1,0,0,0,0,0},
{0,0,1,0,0,0,0},
{0,0,0,1,0,0,0},
{0,0,0,0,1,0,0},
{0,0,0,0,0,1,0},
{0,0,0,0,0,0,1},
};
PrintMatrix(7, TestMatrix);
return 0;
}
int PrintMatrix(int dim, double matrix[dim][dim]) {
int aa, bb;
for (aa = 0; aa < dim; aa++) {
for (bb = 0; bb < dim; bb++) {
printf("%lf ", matrix[aa][bb]);
}
printf("\n");
}
}
The code in the question is an appalling non-compiling mess. One of the comments is:
It still isn't returning the identity for dim = 2 up to 7; any thoughts?
As BluePixy hinted, if you lie to your compiler about the size of the input matrix to the function, for example by passing a 7x7 matrix but telling that it has a 3x3 matrix, it gets its revenge by printing different information from what you wanted. Don't lie to the compiler!
If you want to print identity matrices of sizes 1..7 from a 7x7 matrix, tell the compiler (function) both the actual size of the matrix and the size you want printed. For an identity matrix, you don't actually need the original matrix — you could synthesize the data.
#include <stdio.h>
static void printIdentityMatrix(int size)
{
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
printf("%4.1f", (i == j) ? 1.0 : 0.0);
putchar('\n');
}
}
int main(void)
{
for (int i = 1; i < 8; i++)
printIdentityMatrix(i);
return 0;
}
For printing the top left square subset of an arbitrarily sized square matrix, you must pass both the size of the data to be printed and the actual size of the matrix.
#include <assert.h>
#include <stdio.h>
static void PrintMatrix(int size, int dim, double matrix[dim][dim])
{
assert(size <= dim);
for (int aa = 0; aa < size; aa++)
{
for (int bb = 0; bb < size; bb++)
printf("%lf ", matrix[aa][bb]);
putchar('\n');
}
}
int main(void)
{
double TestMatrix[7][7] =
{
{1,0,0,0,0,0,0},
{0,1,0,0,0,0,0},
{0,0,1,0,0,0,0},
{0,0,0,1,0,0,0},
{0,0,0,0,1,0,0},
{0,0,0,0,0,1,0},
{0,0,0,0,0,0,1},
};
for (int i = 1; i < 8; i++)
{
PrintMatrix(i, 7, TestMatrix);
putchar('\n');
}
return 0;
}
Printing an arbitrary rectangular submatrix of an arbitrarily sized rectangular matrix requires many more function parameters (7 if I am counting correctly:
void PrintSubMatrix(int x_off, int y_off, int x_len, int y_len, int x_size, int y_size,
double matrix[x_size][y_size]);
and that's before you specify the file stream to write on.
#include <assert.h>
#include <stdio.h>
static void PrintSubMatrix(int x_off, int y_off, int x_len, int y_len, int x_size, int y_size,
double matrix[x_size][y_size])
{
assert(x_off >= 0 && x_off < x_size && x_off + x_len <= x_size);
assert(y_off >= 0 && y_off < y_size && y_off + y_len <= y_size);
printf("SubMatrix size %dx%d at (%d,%d) in M[%d][%d]\n",
x_len, y_len, x_off, y_off, x_size, y_size);
for (int x = x_off; x < x_off + x_len; x++)
{
for (int y = y_off; y < y_off + y_len; y++)
printf("%4.1f ", matrix[x][y]);
putchar('\n');
}
putchar('\n');
}
int main(void)
{
double TestMatrix[7][9] =
{
{ 1, 2, 3, 4, 3, 2, 1, 2, 3 },
{ 2, 1, 9, 8, 4, 6, 0, 0, 1 },
{ 3, 0, 8, 7, 5, 5, 0, 0, 1 },
{ 4, 0, 5, 6, 6, 8, 4, 4, 4 },
{ 5, 0, 1, 4, 7, 9, 0, 0, 1 },
{ 6, 0, 1, 0, 8, 1, 0, 0, 1 },
{ 7, 0, 0, 0, 9, 0, 1, 0, 1 },
};
PrintSubMatrix(0, 0, 7, 9, 7, 9, TestMatrix);
for (int i = 1; i < 4; i++)
{
for (int j = 2; j < 4; j++)
PrintSubMatrix(i, j, 3 + j - i, i + j, 7, 9, TestMatrix);
}
return 0;
}
Sample run:
SubMatrix size 7x9 at (0,0) in M[7][9]
1.0 2.0 3.0 4.0 3.0 2.0 1.0 2.0 3.0
2.0 1.0 9.0 8.0 4.0 6.0 0.0 0.0 1.0
3.0 0.0 8.0 7.0 5.0 5.0 0.0 0.0 1.0
4.0 0.0 5.0 6.0 6.0 8.0 4.0 4.0 4.0
5.0 0.0 1.0 4.0 7.0 9.0 0.0 0.0 1.0
6.0 0.0 1.0 0.0 8.0 1.0 0.0 0.0 1.0
7.0 0.0 0.0 0.0 9.0 0.0 1.0 0.0 1.0
SubMatrix size 4x3 at (1,2) in M[7][9]
9.0 8.0 4.0
8.0 7.0 5.0
5.0 6.0 6.0
1.0 4.0 7.0
SubMatrix size 5x4 at (1,3) in M[7][9]
8.0 4.0 6.0 0.0
7.0 5.0 5.0 0.0
6.0 6.0 8.0 4.0
4.0 7.0 9.0 0.0
0.0 8.0 1.0 0.0
SubMatrix size 3x4 at (2,2) in M[7][9]
8.0 7.0 5.0 5.0
5.0 6.0 6.0 8.0
1.0 4.0 7.0 9.0
SubMatrix size 4x5 at (2,3) in M[7][9]
7.0 5.0 5.0 0.0 0.0
6.0 6.0 8.0 4.0 4.0
4.0 7.0 9.0 0.0 0.0
0.0 8.0 1.0 0.0 0.0
SubMatrix size 2x5 at (3,2) in M[7][9]
5.0 6.0 6.0 8.0 4.0
1.0 4.0 7.0 9.0 0.0
SubMatrix size 3x6 at (3,3) in M[7][9]
6.0 6.0 8.0 4.0 4.0 4.0
4.0 7.0 9.0 0.0 0.0 1.0
0.0 8.0 1.0 0.0 0.0 1.0
It would be better if the code was fixed not to print a blank at the end of each line; that's left as an exercise for the reader.

How do I format decimals in C?

This is my print statement:
printf("%d %f\n",kPower, raisePower);
This is my output:
-4 0.000100
-3 0.001000
-2 0.010000
-1 0.100000
0 1.000000
1 10.000000
2 100.000000
3 1000.000000
4 10000.000000
I want it to be printed like this:
UPDATE
So I made my positive values line up:
-4 0.0
-3 0.0
-2 0.0
-1 0.1
0 1.0
1 10.0
2 100.0
3 1000.0
4 10000.0
This is my new code so far:
printf("%d %10.1f\n",kPower, raisePower);
I don't know, should I make a for loop to print each one (positive results vs negative result) in a different format?
#include <stdio.h>
char *get_number_formatted(double f)
{
static char buf[128]; // this function is not thread-safe
int i, j;
i = snprintf(buf, 128, "%20.10f", f) - 2;
for (j = i - 8; i > j; --i)
if (buf[i] != '0')
break;
buf[i + 1] = '\0';
return buf;
}
int main(void)
{
int i;
for (i = -4; i < 5; ++i)
printf("%5d %s\n", i, get_number_formatted(pow(10.0, i)));
return 0;
}
http://ideone.com/KBiSu0
Output:
-4 0.0001
-3 0.001
-2 0.01
-1 0.1
0 1.0
1 10.0
2 100.0
3 1000.0
4 10000.0
printf() cannot print a variating length of decimal digits, so basically what I did was print the formatted number into a buffer and then cut the exceeding zeros.
Try calculating the powers first using pow() from math.h and then:
You can use %10f to precede the number with blanks in the example total of 10 spaces:
printf ("Preceding with blanks: %10f \n", 10000.01);
Source: cplusplus.com
Basicly you can use variable length to perform this:
printf("%d %.*lf", kPower, -kPower, raisePower);
Advantage over other methods is that this method does not need any extra buffer(s)
With a little help of modf, you can use %g to skip the trailing zeroes and \b to skip the leading zero:
#include <stdio.h>
#include <math.h>
int main(void)
{
int i, iarr[] = {-4, -3, -2, -1, 0, 1, 2, 3, 4};
double darr[] = {0.0001, 0.001, 0.01, 0.1, 1., 10., 100., 1000., 10000.};
double intpart, fractpart;
for (i = 0; i < 9; i++) {
fractpart = modf(darr[i], &intpart);
if (fractpart == 0.0)
printf("%10d%10d.0\n", iarr[i], (int)intpart);
else
printf("%10d%10d\b%g\n", iarr[i], (int)intpart, fractpart);
}
return 0;
}
Output:
-4 0.0001
-3 0.001
-2 0.01
-1 0.1
0 1.0
1 10.0
2 100.0
3 1000.0
4 10000.0
Try this example code
float y[7]={0.000100f,0.0010f,0.0100,0.1000f,1.0f,10.000f,100.00f};
int a[7]={-4,-3,-2,-1,0,1,2};
for(int i=0;i<7;i++)
printf("%2d%20f\n",a[i],y[i]);
Output will like that.
You can use sprintf and then trim the zeros. This is the same idea as #Havenard's answer, but writing spaces over the zeros instead of cutting the string.
And my C-style is somewhat different FWIW. My style is that I don't want to count or do any arithmetic in my head; that's what the C optimizer is for :).
#include <math.h>
#include <stdio.h>
#include <string.h>
int main() {
int kPower;
for(kPower=-4; kPower<5; kPower++){
enum { bufsize = 2+5+10+1+4+1+1 };
char buf[bufsize];
int j,n,i;
double raisePower = pow(10,kPower);
//printf("%2d %10.4f\n",kPower,raisePower);
snprintf(buf,bufsize,"%2d %10.4f\n",kPower,raisePower);
j=strchr(buf,'.')-buf;
j+=1;
n=strchr(buf+j,'\n')-buf;
for (i=n-1; i>j; i--)
if (buf[i]=='0')
buf[i]=' ';
else
break;
printf("%s",buf);
}
return 0;
}
Output:
-4 0.0001
-3 0.001
-2 0.01
-1 0.1
0 1.0
1 10.0
2 100.0
3 1000.0
4 10000.0
use printf like this:
printf( "%5d %10.1f\n",kPower, raisePower);
this will result in kPower being printed,
right justified,
in 5 columns
- sign in the right place
this will result in raisePower being printed with:
10 columns
leading 0s replaced by spaces
except 1 digit (could be 0) to the left of the decimal point
1 (rounded) digit to the right of the decimal point
- signs being printed at the proper location
decimal point being aligned

Resources