-2

maybe this is a very easy question but I'm confused

If my code is named example.c and takes as an input a txt file, lets say txt.txt . I run the command ./example txt.txt in a terminal (linux). According to what the user gives me through the file, I create a 2D array. If the context of the fie is:

+X..XX....-
.X..X..X-..
.X.........
...XX......
XXX.+X.....
..X.....XXX
...XXX..X-.
.-.....X...

I count the lines (in this example 1) and the elements before the new line, to find the rows of my array.

Can you please tell me what I do wrong in the printing of the file into a 2d array?

I can't print the array properly.

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv){
    int lines=0, rows=0, j, k;
    char ch, array[1000][1000];
    FILE *fin;

    if(argc!=2){
        exit(2);
    }

    fin=fopen(argv[1],"r");

    if(fin==NULL) {
        exit(2);
    }
    while(!feof(fin)){
        ch=fgetc(fin);
        if(ch=='\n') lines++;
    }

    fclose(fin);
    fin=fopen(argv[1],"r");

    while(!feof(fin)){
        ch=fgetc(fin);
        if(ch=='+' ||ch=='-'|| ch=='.'||ch=='X') rows++;
        if(ch=='\n') break;
    }

    printf("%d %d\n", lines, rows);
    fclose(fin);
    fin=fopen(argv[1],"r");

    while(!feof(fin)) {
        for(j=0; j<lines; j++){
            for(k=0; k<rows; k++){
                scanf(fin, "%c", &array[j][k]);
            }
        }

        //printf("%d %d", lines, rows);
        int i;
        for(i=0; i<lines; i++){
            for(j=0; j<rows; j++){
                printf("%c", array[i][j]);
                //printf("%d %d\n", i, j);

            }
        }
        fclose(fin);
        return 0;
    }
}
Kent Kostelac
  • 2,257
  • 3
  • 29
  • 42
mariatsamp
  • 49
  • 7
  • Your program reads the first line only. Also, can you provide a sample input and expected output? What are you really trying to achieve? – Nandakumar Edamana Apr 13 '18 at 00:15
  • I am just testing if it scanfs properly the input. – mariatsamp Apr 13 '18 at 00:19
  • 2
    See also [why `while(feof(file))` is always wrong](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) – Pablo Apr 13 '18 at 00:22
  • @Pablo what would u suggest? – mariatsamp Apr 13 '18 at 00:41
  • 1
    Use `int ch; ... while ((ch = fgetc(fin)) != EOF) { ... }` – chux - Reinstate Monica Apr 13 '18 at 00:42
  • 1
    I don't know about others, but I do not want to spend my time examining a program, trying to determine control flow, etc. Therefore, for ease of readability and understanding: 1) separate code blocks ( `for` `if` `else` `while` `do...while` `switch` `case` `default` ) via a single blank line. 2) consistently indent the code. Indent after EVERY opening brace '{'. unindent before every closing brace '}'. Suggest each indent level be 4 spaces. 3) follow the axiom: *only one statement per line and (at most) one variable declaration per statement.* – user3629249 Apr 13 '18 at 00:52
  • when calling `fopen()`, always check (!=NULL) the returned value. If NULL, then call `perror()` to output your text and the reason the system thinks the function failed to `stderr` – user3629249 Apr 13 '18 at 00:53
  • when the incorrect count of command line parameters is recognized, the code should output a `USAGE` message to `stderr`,, similar to `fprintf( stderr, "USAGE: %s [type of parm1] [...] \n", argv[0] );` then call `exit()` – user3629249 Apr 13 '18 at 01:03
  • regarding: `char ch, array[1000][1000];` 1) for readability should be two lines: the declaration of `array[][]` places a 1000000 byte array on the stack. This is not a good idea. Suggest using something similar to `char *array = malloc( 1000*1000 ); if (!array) { perror( "malloc failed" ); exit( EXIT_FAILURE ); } – user3629249 Apr 13 '18 at 01:06
  • regarding: `while(!feof(fin)){ ch=fgetc(fin);` suggest using `fgets()` similar to: `while( (ch = fgetc( fin )) != EOF );` Note: these lines: `fclose(fin); fin=fopen(argv[1],"r");` would be better written as: `rewind( fin );` – user3629249 Apr 13 '18 at 01:11
  • regarding: ` fclose(fin); return 0;` they should be just before the final `}`, not just before the last two: `}}` – user3629249 Apr 13 '18 at 01:14
  • the last `while()` loop can be reduced to: `char line[1000]; while( fgets( line, sizeof( line ), fin ) ) { printf( "%s", line ); } fclose( fin ); return 0;` – user3629249 Apr 13 '18 at 01:18
  • I have to agree with @user3629249. it 's a real smack in the face that you don't use proper indentation. Especially when you ask for help from thousands of strangers. – Kent Kostelac Jul 28 '18 at 19:22

2 Answers2

3

You have several problem in your code

  1. See why while(foef(file)) is always wrong. If you are going to read the file character by characters, it's best to do it this way:

    int c;
    while((c = getchar()) != EOF)
    {
        // do somthing with c
    }
    
  2. Reading the values like this fscanf(fin, "%c", &array[j][k]); it's ok, but it has one problem: you are forgetting to take the newline into account. You are only reading row number of characters, but the whole line (assuming there are no empty spaces and tabs) has row+1 characters, the newline didn't go away, so when you are finishing reading the last value of a row, the next scanf will not read the next value, it will read a newline. You can fix it by doing this:

    for(j=0; j<lines; j++){
        for(k=0; k<rows; k++){
            fscanf(fin, "%c", &array[j][k]);
    
        getchar(); // consume the newline
    }
    

In general you should read the values line by line using fgets and then you can use sscanf to parse the line.

So, to determine the number of lines:

int lines = 0;
int c, last = '\n';
while((c = fgetc(fin)) != EOF)
{
    last = c;
    if(c == '\n')
        lines++;
}

// in case the last line does not end with \n
// some file editors don't end the last line with \n
if(last != '\n')
    lines++;

To get the number of rows:

int rows = 0; 
while((c = fgetc(fin)) != EOF)
{
    // based on your example, the file does not
    // contains other characters than +,-,.,X and newlines
    if(ch == '\n')
        break;
    else
        rows++;
}

and now to read the values:

// assuming that the file has the correct format and that
// all lines have the same length
char line[rows+2];  // +2 because of the newline and the 0 terminating byte

for(int i = 0; i < lines && i < 1000; ++i)
{
    fgets(line, sizeof line, fin);
    char *tmp = line;
    for(int j = 0; j < rows && j < 1000; ++j)
        sscanf(tmp++, "%c", &array[i][j]);
}

Note that this code that the file has the proper format and that all lines have the same length. In order to make the reading more robust (that means that it can react to format errors) you'll need to check the return value of fgets and sscanf. I've omitted that for sake of simplicity, but you should add these checks.

And you don't need to open and close fin every time, you can use rewind(fin) to set the file at the beginning.

Pablo
  • 13,271
  • 4
  • 39
  • 59
  • @Pablo do u believe that a use of a getline function is much more suitable than all that? Is there any simpler way that will eliminate all these possible mistakes? – mariatsamp Apr 13 '18 at 00:59
  • @doomandgloom if you're working with a POSIX systems and `getline` is available to you, then yes, you can use that. You would reduce a lot of the code and have less places where things can go wrong. – Pablo Apr 13 '18 at 01:01
0

You can read the first line to get the number of rows.

// Read first line char by char
char ch = fgetc(fin);
while (ch != '\n' && !feof(fin)) {
    rows++;
    ch = fgetc(fin);
}

Read remaining lines to get number of lines

// Read remaining lines
while (!feof(fin)) {
    if (ch == '\n')
        lines++;
    ch = fgetc(fin);
}

Initialize array based on number of lines and rows and read through the file once again. Put non-newline characters to the appropriate location of the array by incrementing j after each character and i after each line.

// Initialize array, read again
rewind(fin);
char array[lines][rows];
printf("%d %d\n", lines, rows);

int i = 0; // Current line
int j = 0; // Current row
ch = fgetc(fin);
while (!feof(fin)) {
    if (ch != '\n') {
        array[i][j] = ch;
        j++;
    }
    else if (ch == '\n') {
        i++;
        j = 0;
    }
    ch = fgetc(fin);
}

Your read part terminates once it reaches end of file.

To print the array, it is a simple double-loop:

// Read array
for (i = 0; i < lines; i++) {
    printf("[");
    for (j = 0; j < rows; j++) {
    printf(" %c ", array[i][j]);
    }
    printf("]\n");
}