How to properly use fscanf to store only the needed information in an array?

1.3k views Asked by At

I'm trying to write a program in c that reads a mtx file (mtx stands for midi to text, it's actually a txt file) and stores only the information I need (specifically only the note-on/off and pitch-bend messages) here's an example: mtx file example

the information that I need are: the timing (first number), the type (On, Off and Pb), the "n=" value and the "v=" value (in pitch-bend messages there's only the "v=" value). I'm not an expert in C language, I know the basics and I based my programming on this guide and this guide.

Here's the code I wrote:

FILE * read_from;
char status[3];
int u = 0;
int ctrl,ct;
read_from = fopen(nomesong, "r");
if (!read_from)
    printf("NO WAY\n");
else{
while (1){
    ct = fscanf(read_from, "%d", array[u][0]);
    if (ct == 1){
        ctrl = fscanf(read_from, " %s", &status);
        if (ctrl == 1){
            if (status[1] == 'n'){
                array[u][1] = 1;
                fscanf(read_from, " ch=1 n=%d v=%d", array[u][2], array[u][3]);
            }
            else if (status[1] == 'f'){
                array[u][1] = 0;
                fscanf(read_from, " ch=1 n=%d v=%d", array[u][2], array[u][3]);
            }
            else if (status[1] == 'b'){
                array[u][1] = 2;
                fscanf(read_from, " ch=1 v=%d", array[u][3]);
            }
        }
        else if (errno != 0) {
            perror("scanf:");
            break;
        }
        else {
            printf("No match.\n");
        }

    }
    else if (errno != 0) {
        perror("scanf:");
        break;
    }
    else if (ctrl == EOF) {
        break;
    }
    printf("%d %d %d %d\n", array[u][0], array[u][1], array[u][2], array[u][3]);
    u++;
}
}return;

As output it prints four zeros per row (array[][] is initialized to 0) then starts spewing out random big numbers, then keeps printing zeros and then stops and VS (2013) emits the "Unhandled exeption" alert message. What am I doing wrong? Any help will be appreciated.

1

There are 1 answers

3
chux - Reinstate Monica On BEST ANSWER

OP's code problems include:

1) Passing a variable, rather than an address of a variable in fscanf(read_from, " ch=1 n=%d v=%d", array[u][2], array[u][3]);

2) Insufficient space reading "Off" with char status[3]; ... ctrl = fscanf(read_from, " %s", &status);

The better approach is to not use fscanf(). Read the line using fgets() or getline() and then scan using sscanf(), strtol(), etc.

// Read  line by line until EOF
while (fgets(buf, sizeof buf, read_from)) {
  // Clear entry
  memset(&array[u], 0, sizeof (array[u]));

  if (3 == sscanf(buf, "%d Off ch=1 n=%d v=%d", 
      &array[u][0], &array[u][2], &array[u][3])) {
    array[u][1] = 1;
  } else if (3 == sscanf(buf, "%d On ch=1 n=%d v=%d", 
      &array[u][0], &array[u][2], &array[u][3])) {
    array[u][1] = 0;
  } else if (2 == sscanf(buf, "%d Pb ch=1 v=%d", 
      &array[u][0], &array[u][3])) {
    array[u][1] = 2;
  } 

Note: as ch=1 is likely not a constant 1, code could use "%*d" to scan and discard the ch number.

  if (3 == sscanf(buf, "%d Off ch=%*d n=%d v=%d", 
      &array[u][0], &array[u][2], &array[u][3])) {
    array[u][1] = 1;
  }