C What is up with my Matrix Reader? - c

so I am trying to make a matrix reader that will take a text file that contains only data for a NxN matrix such as:
10 9 8 7
6 5 4 3
2 1 0 1
Read the test file into a dynamic multidimensional array. The program will not have headers, so it will need to read the entire file in order to obtain # of rows/cols.
Once I have all the data in my array I then will be able to manipulate how I want (i.e. swapping columns/rows, reversing order, etc).
At this point I am just trying to get my program to simply output the array as it appears in the test file once the entire matrix has been read in.
Here is what I have written so far:
#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
int i=0;
int j=0;
scanf("%d", &n);
int **array;
array = malloc(n * sizeof(int *));
if(array == NULL) {
printf("Out of memory\n");
exit(1);
}
for(i = 0; i < n; i++) {
array[i] = malloc(n * sizeof(int));
if(array[i] == NULL) {
printf("Out of memory\n");
exit(1);
}
}
for(i = 0; i < n; i++) {
for(j = 0; j < n; j++) {
int k;
scanf("%d", &k);
array[i][j] = k;
printf("%d ", array[i][j]);
}
}
}
And running this gives me output:
9 8 7 6 5 4 3 2 1 0 1 1 1 1 1 1 1 1 1 1 1 1... repeating 1's...
I am not sure what is wrong with my code I have been staring at it for a solid hour and have made 0 progress.
Because my output prints out about 100 different ints I feel that my problem lies in my printing loops, and I feel like it has something to do with int n, but I am not sure how to deal with this.
Any help with be greatly appreciated! Thanks.

The issue is as follows: The first number that is obtained from your file is 10 and that is being stored inside the int n close towards the beginning. That value defines the width and height of your multi-dimensional array, your matrix. You then ask for further values from that file, exactly 10 * 10 many times.
The file, however, only has 4 * 3 - 1 = 11 numbers left in it. It provides them all, right into the int k. Those values get stored inside your matrix, printed. After the 11th (or 12th if you count the first 10) the scanf starts failing. As it fails, it returns the value EOF == -1 but you do not recognize that.
Failure leaves the k as it is, although I am not sure whether it is guaranteed to remain what it previously was, since as far as I know, k could very well have another memory location allocated for itself with each cycle, since (again) as far as I know it gets cleared at the end of each loop. In your case, it does keep its value, luckily I would say, and that gets stored/printed.
In the end, you should have exactly 100 numbers printed, because of that 10 at the very beginning.
Even if you had an additional 4 at the very beginning, you'd end up with a matrix that has a wild last line with all 1s.
If you want to have a 3 by 4 matrix in your hands, consider making your file as the following example:
3 4
10 9 8 7
6 5 4 3
2 1 0 1
Then read the first value into an int n and then second one into an int m. Make first memory allocation with malloc( n * sizeof * array );, then the secondary allocations with malloc( m * sizeof ** array );.
You could also alternatively omit reading anything, deduce how many rows and columns your matrix should have by reading the amount of new-line '\n' occurrences in your file (plus one), as well as amount of numbers there are on a single line.
Edit:
Okay, let's show this you could also part: This is just an example, I'll be using a pair of scanfs for counting both the amount of lines that have at least one number inside and amount of numbers on a single line.
...
int n = 0;
int m = 0;
int discardable;
while ( scanf( "%d", &discardable ) == 1 ) {
// as long as a number has been successfully read
n++;
if ( scanf( "%*[^\n]" ) != 0 )
// discard everything until a '\n'
// and if you fail to encounter a '\n' anywhere until the file ends...
break;
}
// rewind back to the beginning of the file
rewind ( stdin );
while ( scanf( "%d", &discardable ) == 1 ) {
// as long as a number has been successfully read
m++;
if ( scanf( "%*[ \t]" ) != 0 || stdin->_ptr[0] == '\n' )
// discard every ' ' or '\t'
// if you rather get carried until the end of file, break
// else, if the upcoming character is '\n', again, break
break;
}
rewind ( stdin );
...
There you have it, n and m here should be storing the height and width of the matrix you should have, respectively.
This is just a way to do it, I can see why many could potentially just hate this, because I have made use of the FILE structure, and referred to _ptr, but whatever. I personally would prefer this any day over carrying a temporary character array and read from it.

Related

Why are these indices not getting the same thing from a 2d malloc'd C array?

Data file I am reading from:
$ cat temp.txt
0 1 2 3
4 5 6 7
8 9 10 11
C code:
#include<stdio.h>
#include<stdlib.h>
void main(){
int matsize = 12;
int numrows = 3;
int numcols = 4;
int** mat=malloc(matsize*sizeof(int*));
for(int i=0;i<numrows*numcols;++i){
mat[i]=malloc(sizeof(int));
}
FILE *file;
file=fopen("temp.txt", "r");
for(int i = 0; i < numrows; i++){
for(int j = 0; j < numcols; j++) {
if (!fscanf(file, "%d", &mat[i][j]))
break;
}
}
fclose(file);
printf("%d\n",mat[numrows-1][numcols-1]);
printf("%d\n", mat[2][3]);
printf("%d\n", mat[1][5]);
printf("%d\n", mat[0][11]);
printf("Done allocating.\n");
}
$ ./a.out
11
11
0
7
The first two outputs are both 11 as expected. For a 12 item array, I was expecting mat[1][5] and mat[0][11] to output the same thing as mat[2][3] (i.e. the 12th element, i.e. the [i+1th][j+1th] element). My understanding is that internally, the array declared here:
int** mat=malloc(matsize*sizeof(int*));
is not really a 2x3 array, rather it's just a matsize array and that accessing it via mat[i][j] just kind of divides it into [i] rows then gets the [jth] element of the ith row. Does the compiler "know" the array should be a 3x4 array because I am reading the text file in with the line if (!fscanf(file, "%d", &mat[i][j])) ? Does this scanning statement permanently change the mat object into 3 pointers of 4-length integer arrays? Or is it really just still a 12-length array, which should be accessible via dividing into two 6's, one 12, etc (if so, then why didn't the last two indexings print out the right thing)?
Follow up: If I change everything from %d/ints to %lf/doubles, I get this output with the same indexing:
11.000000
11.000000
9.000000
11.000000
Why is, for example, mat[0][11] coming out to 7 when everything is an int, but 11.000000 (as expected) when things are floats?
You should allocate a 2D array instead. It can be done as
int (*mat)[rows][cols] = malloc( sizeof(int[rows][cols]) );
However, to enable the conventient mat[i][j] syntax, you have to drop one of the dimensions in the pointer type:
int (*mat)[cols] = malloc( sizeof(int[rows][cols]) );
Not only does this get rid of the needless complexity and bugs, it also enables you to read the whole file with a single fread call, since you have a real 2D array now, instead of some fragmented pointer-to-pointer thing.
Don't forget the free(mat); at the end.

bits and arrays in C - New to programming

I have a given code from school, I need this as my output:
Digital Binair
0 is 000,
1 is 001,
2 is 010,
3 is 011,
4 is 100,
5 is 101,
6 is 110,
7 is 111
(3 bits)
I need to work with for loops, this is the given code:
#include <stdio.h>
#include <string.h>
#define ZERO '0'
#define ONE '1'
int main(void)
{
char rij[8][4];
int n, m;
strcpy( rij[0], "000" );
printf( "%s\n", rij[0] );
for ( n=1; n<8; n++ )
{
strcpy( rij[n], rij[n-1] );
printf( "%s\n", rij[n] );
// *ONLY ABLE TO TYPE IN HERE !!!! THE REST IS GIVEN !!!!*
}
for( n=0; n<8; n++ )
{
printf( "%i %s\n", n, rij[n] );
}
return 0;
}
I'm stuck at is how do I make a for loop that is working with bits. So lets say for(n = 0; n < 8; n++) how do I make the loop go form 000 to 001 to 010.
While there are many ways of generating a binary sequence, here the task appears to have been deliberately complicated (or made interesting) by the constraint that you modify code only at the location indicated and the initialisation of each successive string with the content of the previous one.
The arrays serve no purpose other than to make you think - it is a purely academic exercise, not a practical application. Each string is initialised with the content of the previous string (which the code you must add will have modified), the intent of the exercise is that you perform a binary "add 1" at each iteration.
To do that, starting from the LSB (rij[n][2]), if the digit is ZERO you set it to ONE, then move to the next n, else you set it to ZERO, and "carry" one, repeating the above process for the next most significant bit in the string n.
You can do that in a loop from the LSB (2) index to the MSB (0) index, and exiting the loop (break) when you set any bit to ONE.
Or for just three digits you can unroll-the loop thus:
if( rij[n][2] == ZERO )
{
rij[n][2] = ONE ;
}
else
{
rij[n][2] = ZERO ;
if( ... // test next bit [1] - enough of a hint I think.

How to get input for arrays whose length is not determined

I am supposed to write a program that "quicksort"s a given array of numbers. The problem is , dynamic memory allocation is not allowed and nor am I given the number of "numbers" that are supposed to be inputs of my program.
For instance, here's an input/output example:
INPUT: 0 1 5 3 6 2 4
OUTPUT: 0 1 2 3 4 5 6
But I just can't seem to be able to close my while loop when getting the numbers using scanf(); (I know , scanf() is silly , but I can't use "iostream" either)
Here's the code I was trying to get to work:
int main()
{
int target_arr[1000], l, h, i = 0, c = 0, k = 0;
while (scanf("%d", &target_arr[i]) != EOF)
{
i++;
}
h = i -1;
l = 0;
quick(l, h, target_arr);
print_arr(target_arr, i );
return 0;
}
quick() and print_arr() functions are previously defined and work perfectly well given the proper input.I just don't know how to stop the loop when I'm done inputting.
Any help would be greatly appreciated.

Creating an index array of all commas in array

I am trying to create an index array that will store the location of every ',' that is read in from a file. I have written the code and it seems to work but for some reason stops after exactly 1 ',' past the first line in the file.
What in the world is causing it to stop I cant figure it out. It just gives zeros after the first couple indexes.
#include <stdio.h>
#include <stdlib.h>
void getCommaIndex(int n,char table[],int index[]){
int i;
int p = 0;
for(i = 0 ; i < n ; i++){
if(table[i] == ','){
index[p] = i;
p++;
}
}
}
int main()
{
char table[100000];
int index[5000];
int i;
FILE *fp;
fp = fopen("C:/Users/Chris/Desktop/Open Frameworks/apps/myApps/bin/data/tableshort.csv","r");
while( !feof(fp)){
fgets(table,"%s",fp);
printf("%s",table);
getCommaIndex(5000,table,index);
}
for(i = 0 ; i < 11 ; i++){
printf("%d ",index[i]);
}
Output will look something like:
7 11 20 35 40 59 62 67 0 0 0 0 0 0
I just changed:
fgets(table,"%s",fp);
to:
fgets(table,5000,fp);
and everything worked.
See: http://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm
Also, your code in your question gave me this message in my compiler: warning: passing argument 2 of 'fgets' makes integer from pointer without a cast. Treat warnings as errors as much as you can.
Instead of reading the entire file at once, you could try reading a single line at a time. Also, in your getCommaIndex function table[] is 100000 but you only iterate over the first 5000 indices. It is not clear to me but it seems like you value for n should be 100000 so you loop over the entire table array.

Generation of 20 random nums in c

#include <stdio.h>
#include <time.h>
int main(int argc,char *argv[])
{
int i;
int array[20];
srand(time(NULL));
for (i=0; i<20; i++)
array[i] = rand()%8999 + 1000;
char *fname = argv[1];
FILE *fp;
fp = fopen(fname,"w");
fwrite(array,sizeof(int),20,fp );
fclose(fp);
return 0;
}
my program should generate a sequence of 20 random numbers within a range of 1000 to 9999. I need to create an array of 20 nums, sort it and transfer to the file passed at cmd line... But, it says Segmentation fault
Your formula for getting the random values is also wrong:
With this code:
rand()%9999 + 1001;
you will get values from [1001, 11000]. When you are claiming you want a range from [1000, 9999].
Try to solve this for a simpler case, lets say a dice from [1, 6] will be:
rand()%5 + 1
The other problem is your for loop:
Remove the for loop and you should be fine. You don't need that for loop to print the array. Check the rewind function if you really need to do something like that.
First check the return value of fopen.
Then:
fwrite(array,sizeof(int),20,fp );
You are not moving your array pointer. Use something like:
fprintf(fp, "%d\n", array[i]);
Also:
array[i] = rand()%9999 + 1001;
What if the value yielded by rand()%9999 is 9998? I think then 9998 + 1001 is no longer between 1000 and 9999. Also how can rand()%9999 + 1001 yields 1000?
for (i=0; i<20; i++)
array[i] = rand()%8999 + 1000; // change random Number logic
for (i=0; i<20; i++)
fprintf(fp,"%d\t",array[i]); // change fwrite(array,sizeof(int),20,fp );
see fprintf()
First problem, the rand calculation is false, if you want an integer between 1000 and 9999, then it should be :
array[i] = rand()%9000 + 1000; // 9000%9000 = 0 ...
Then, your call to fwrite writes the whole content of the array buffer, seen as a set of sizeof (int) long substrings. Since odds are quite low that you will end up with valid character encoding, when you will open your file with a text editor to see the results, you will only have gibberish data ... Thus, your whole for loop is useless (you will print 20 times the whole content of array subsequently to your file).
Here, what you could do is a for loop with a call to fprintf to write the array[i] number in a human readable format or just stick with your single call to fwrite.
Then, I would like to say that you do not test the return value of your function calls.
It can be a source of errors so be very careful with this. I think of the whole file operation functions (fopen, fwrite).
Then, what if argv[1] doesn't exist ? When the call to fopen will be run, you'll have a segmentation fault ... Here is a little checking you could add :
if (argc > 1) {
fname = argv[1];
} else {
fname = NULL;
}

Resources