Scanf function with variable amount of parameters, how to implement?

Asked

Viewed 3,650 times

4

I have a text file (txt) that contains the following values:

12 90

These two values I keep and my variables a and b, that is to say a is equal 12 and b is equal 90, and I’m using the function scanf() to receive these values from the file as follows:

#include <stdio.h>

int main()
{
    int a, b;

    scanf("%d %d", &a, &b);

    printf("Valor a = %d, b = %d", a, b);

    return(0);
}

Exit:

Value a = 12, b = 90

I run the program with the following command scanfTeste.exe < arquivo.txt in the prompt Windows to run the program.

However, the structure of my file will change, time it will have two values or an indeterminate amount, see the examples:

  • Example one of the file content: 12 90
  • Example two of file content: 12 90 33 77

Whereas the values are separated by spaces to facilitate the reading of the data.

My doubt:

As you can see the amount of parameters you pass to scanf("%d %d ...", &a, &b, ...) changes depending on the amount of values in the file row, as I can make the function scanf() receive a number of parameters according to the amount of values in the file line?

  • 1

    Do you know the number of elements or not? If you do not know, the solution you are asking for does not work.

  • Yes, one of the values indicates the amount of elements in the file, and the first value and then the values.

  • 1

    I think using a loop that reads a value at a time will be easier and simpler than trying to make a smart scan.

  • @hugomg yes I implemented in a loop with fscanf and it worked.

  • 1

    The description of your question was very good! :)

3 answers

4


One of the ways is to use normal reading adapting to needs, something like that:

char arquivo[] = "1 2 3 4 5";
int a, b, c, d, e;
sscanf (arquivo, "%d %d %d %d %d", &a, &b, &c, &d, &e);
printf ("%d - %d - %d - %d - %d", a, b, c, d, e);

Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.

You obviously need to use the fscanf() which is correct for file and not what I used for easy.


Another possibility, seems to me the best, if you do not want to create all variables and to make it easier to read would read one by one in a loop. Something like this:

int i = 0;
int tamanho = 5;
int array[tamanho];
FILE * arquivo = fopen("file.txt", "r");
while (fscanf(arquivo, "%d", &array[i++]) == 1);

I put in the Github for future reference.


You can also do this in lists of variable size with vfscanf() giving more flexibility, allowing to specify the format of the data that will be received at each position. I never used and don’t have the details, but the documentation provides this example:

#include <stdio.h>
#include <stdbool.h>
#include <stdarg.h>
 
bool checked_sscanf(int count, const char* buf, const char *fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    int rc = vsscanf(buf, fmt, ap);
    va_end(ap);
    return rc == count;
}
 
int main(void) {
    int n, m;
    printf("Parsing '1 2'...");
    if(checked_sscanf(2, "1 2", "%d %d", &n, &m)) puts("success");
    else puts("failure");
    printf("Parsing '1 a'...");
    if (checked_sscanf(2, "1 a", "%d %d", &n, &m)) puts("success");
    else puts("failure");
}

I put in the Github for future reference.

2

Good if you want to read until the end of the file do so:

#include<stdio.h>

int main(){
    int a[30], n = 0;

    while(scanf("%d", &a[n++]) != EOF && n < 30)
        printf("a[%d] = %d, ", n-1, a[n-1]);
}

The scanf returns EOF when it reaches the end of the file and has nothing else to read, comparing this you know when the file is finished!

Entree:
2 4 23
55 12

Exit:
a[0] = 2, a[1] = 4, a[2] = 23, a[3] = 55, a[4] = 12,

If you just want to read until you finish the line it gets a little more complicated:

#include<stdio.h>

int main(){
    int a[30], n = 0, c;
    char linha[512], *plin;

    scanf("%510[^\n]", linha);
    plin = linha;

    while(sscanf(plin, "%d%n", &a[n++], &c) != EOF && n < 30){
        printf("a[%d] = %d, ", n-1, a[n-1]);
        plin += c;
    }
}

Entree:
2 4 23
55 12

Exit:
a[0] = 2, a[1] = 4, a[2] = 23,

Note that this time he only read the first line. The %d of the scanf will not warn you when you skipped a line, it just swallows and line and passes to next. So if you read only the line first with the %[ n] limiter, which reads until you find an n and then use sscanf on that line, you can read only the integers of the line!

Remembering that I put a limit of up to 30 numbers, you can increase the limit or make a malloc if 30 is not enough.

Just like you used scanfTeste.exe < arquivo.txt to run the program. It would be right to open the file and use with fscanf

0

In addition to the above, I have added a variant for the:

  • each row has a variable number of integers, max. N (example N=4)
  • we intend to read them, and know how many were
  • we are taking advantage of the fact that scanf returns the number of items read. The function scanf is good for "read up to N elements..."
#include <stdio.h>

int main(){
   int i,n, a[4];
   char s[1000];
   while((n=sscanf(fgets(s,1000,stdin),"%d%d%d%d",
                   &a[0], &a[1], &a[2], &a[3])) != EOF ){
      for(i=0; i<n; i++) printf("%d ",a[i]);
      printf(" (%d elems)\n",n);
  }
  return 0;
}

Entree

1 2 3
1
2 3 4 5

exit

1 2 3   (3 elems)
1   (1 elems)
2 3 4 5  (4 elems)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.