-1

I'm trying to edit out the semicolons in a matrix that I'm receiving as an input file and I just can't seem to make any progress. I've used while loops in main to determine the dimensions of the matrix because the program needs to be able to handle matrices of different sizes. I do know that it will always be a square matrix. I think my problem is in the read_file function. I can read in the matrix from the file and printf it to the terminal but I can't remove the semicolons. I've tried several different ways, including strtok, but I always end up with junk data. The following code will read in the input file and printf to the terminal without errors or warnings, but it includes the semicolons that I need to remove. Here is my code:

void read_file(int *rows_p, int *columns_p, char matrix[*rows_p][*rows_p], char *file[]){

    FILE *file_in;
    file_in = fopen(file[1], "r");

    /*Please not that the next few declarations and nested loops are commented out. I thought I should show this failed attempt.*/

    /*char temp[*rows_p];
    int new_col = (*columns_p + 1) / 2;
    int i = 0;
    int j;
    int k;

    while(fgets(temp, *columns_p, file_in) != NULL){
        int ii = 0;
        for(j = 0; j < *columns_p; j += 2){
            if((temp[i] == '1') || (temp[i] == '0')){
                matrix[i][ii] = temp[j];
                ii++;
            }
        }
        printf("%s", matrix[i]);
        i++;
    }
    printf("\n");
    */

    char temp[*rows_p][*columns_p];
    int i = 0;
    int j;
    int k;

    while(fgets(temp[i], *columns_p, file_in) != NULL){
        for(j = 0; j < *columns_p; j++){
            if((temp[i][j] == '1') || (temp[i][j] == '0')){
                strcpy(matrix[i], temp[i]);
            }
        }
        printf("%s", matrix[i]);
        i++;
    }

    fclose(file_in);
}

And here is what is in the input file (the input file is a .csv):

0;0;0;0;0;0
0;0;0;1;0;0
0;1;0;1;0;0
0;0;1;1;0;0
0;0;0;0;0;0
0;0;0;0;0;0

This will eventually be for a Game of Life program but I find myself stuck not being able to remove the semicolons. I've done similar edits before but I just can't seem to figure this one out. Assistance would be greatly appreciated.

The output that I want to achieve is,

000000
000100
010100
001100
000000
000000

I'm expecting this to be the easiest form to manipulate the matrix in.

Brian.H
  • 73
  • 1
  • 7
  • 1
    So you want to replace `;` or remove them? Also what do you expect out of it? The buffer on which you read, you want to store the result? `";"` and `';'` they are different. Show the sample output you want. – user2736738 Jan 27 '18 at 19:02
  • Welcome to Stack Overflow. Please take the [tour] and read [ask] and [mcve]. – Pablo Jan 27 '18 at 19:06
  • Why opening/closing same file multiple times? Try `rewind()`. You can also find out the number of rows and columns in only one parse, no need to scan the whole file twice. – H.S. Jan 27 '18 at 19:09
  • Why don't you try a little search in stackoveflow? https://stackoverflow.com/questions/3463426/in-c-how-should-i-read-a-text-file-and-print-all-strings – Nikolas Jan 27 '18 at 19:17
  • I updated my post with the output that I'm looking to get. I had never heard of rewind() until now. I will use that. And I've looked at many previous posting on stackoverflow but I could get the desired result. – Brian.H Jan 28 '18 at 00:20
  • Update: That rewind() suggestion was a lot more help than I would've guessed it to be! Because of looking into rewind() I found fseek(). fseek() REALLY helped me copy the file to a 1D string. From there I was to iterate through that array and transform it into the 2D matrix that I needed! Most of the code I posted I deleted. Thanks for the help. – Brian.H Jan 28 '18 at 04:37

1 Answers1

0

While there is nothing wrong with using fgets and a line-oriented approach to separating the values in your .csv file, you may find a character oriented approach a bit more intuitive to begin with.

In either case, you shouldn't limit your tests to '0' or '1' characters as 2-9 can also make up any number. A generic test for a digit using isdigit from ctype.h can handle all values.

Regardless whether you use a line-oriented or character-oriented approach, the goal is the same, you will either locate the position in your line at the start of each number and call strtol (or strtoul or strtod as appropriate) to covert a string of digits to a numeric value, or you buffer the digits a character at a time and call your conversion function on the buffer. (implementing the conversion call is left to you)

Here, separating the values seems to be the current stumbling block. Where taking a character-oriented approach may help is to build an understanding of working though a string of characters one-at-a-time, testing, and taking the proper action based on the current character. From a file read standpoint, it couldn't be simpler, just open the file and read a character at a time until your reach the end-of-file and EOF.

Looping a character at a time, you need to keep the track of the current read-state (am I reading digits, or a separator?) You base your column count on the transitions from digits to separators (or '\n' or EOF). You base your row count on '\n' or EOF). Then it is just a matter of validating you have the same number of values in each row (for a matrix) and that when your read is complete you have the same number of rows as columns. (you should also insure you handle any two separators together -- that is left to you)

A short example of a character-oriented read to parse you matrix from the file could be done as follows without limiting yourself to just '0' and '1',

#include <stdio.h>
#include <ctype.h>

int main (int argc, char **argv) {

    int c,              /* char read from file */
        rows = 0,       /* matrix rows */
        cols = 0,       /* matrix cols */ 
        nvals = 0,      /* values per row count */
        havedigit = 0;  /* flag - reading digits - 1 */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    for (;;) {                      /* loop until EOF */
        c = fgetc(fp);              /* get a character */
        if (isdigit(c)) {           /* test if digit */
            havedigit = 1;          /* set havedigit flag */
            putchar (c);            /* output char */
        }   /* end-of-row or end-of-file */
        else if (c == '\n' || c == EOF) {
            if (havedigit) {        /* prev char read was digit */
                nvals++;            /* increment value count */
                putchar ('\n');     /* output newline */
            }
            if (c == EOF)           /* if EOF - bail */
                break;
            if (rows == 0)          /* if first row, set cols */
                cols = nvals;
            else if (nvals != cols) { /* validate no. of cols */
                fflush (stdout);    /* output any bufferd chars */
                fprintf (stderr, "\nerror: not a valid matrix.\n");
                return 1;
            }
            rows++;             /* increment row count */
            nvals = 0;          /* reset value per row count */
            havedigit = 0;      /* set digit flag to zero */
        }
        else {                  /* we have a separator */
            if (havedigit)      /* if last was digit */
                nvals++;        /* increment value per row */
            havedigit = 0;      /* set digit flag to zero */
        }
    }

    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    if (rows != cols) { /* validate rows == cols for sq. matrix */
        fprintf (stderr, "error: not a square matrix.\n");
        return 1;
    }

    return 0;
}

There are many, many ways to approach parsing the file. Working though several methods will help you recognize which fits each type of parsing problem best.

Example Input Files

$ cat dat/matrix.csv
0;0;0;0;0;0
0;0;0;1;0;0
0;1;0;1;0;0
0;0;1;1;0;0
0;0;0;0;0;0
0;0;0;0;0;0

$ cat dat/matrix2.csv
0;0;0;0;0;0;1;0
0;0;0;1;0;0;0;1
0;1;0;1;0;0;1;0
0;0;1;1;0;0;0;1
0;0;0;0;0;0;1;1
0;0;0;0;0;0;0;0
1;1;1;0;0;1;1;1
0;0;0;1;1;0;0;0

Example Use/Output

$ ./bin/getchar_parse_matrix <dat/matrix.csv
000000
000100
010100
001100
000000
000000

$ ./bin/getchar_parse_matrix <dat/matrix2.csv
00000010
00010001
01010010
00110001
00000011
00000000
11100111
00011000

Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85