Reading from two columns to variables

I am writing a C program that takes an input file and saves it. The input file has two columns with an integer in the first and a row in the second, for example:

12 apple 17 frog 20 grass 

I tried using fgets to take the whole line as a string and then split it with scanf, but I am having a lot of problems. I searched a lot, but did not find anything that could answer my question, but I'm sorry if I missed something obvious. This is the code I tried:

  while(fgets(line, sizeof(line), fp)) { scanf(line, "%d\t%s", &key, value); insert(key, value, newdict); } 
+4
source share
4 answers

Let me go quickly to strtok , as someone mentioned this. Imagine your file is called file.txt and has the following contents:

 10 aaa 20 bbb 30 ccc 

Here's how we can make it out:

 #include <stdio.h> #include <string.h> #define MAX_NUMBER_OF_LINES 10 // parse a maximum of 10 lines #define MAX_LINE_SIZE 50 // parse a maximum of 50 chars per line int main () { FILE* fh = fopen("file.txt", "r"); // open the file char temp[MAX_LINE_SIZE]; // some buffer storage for each line // storage for MAX_NUMBER_OF_LINES integers int d_out[MAX_NUMBER_OF_LINES]; // storage for MAX_NUMBER_OF_LINES strings each MAX_LINE_SIZE chars long char s_out[MAX_NUMBER_OF_LINES][MAX_LINE_SIZE]; // i is a special variable that tells us if we're parsing a number or a string (0 for num, 1 for string) // di and si are indices to keep track of which line we're currently handling int i = 0, di = 0, si = 0; while (fgets(temp, MAX_LINE_SIZE, fh) && di < MAX_NUMBER_OF_LINES) // read the input file and parse the string { temp[strlen(temp) -1] = '\0'; // get rid of the newline in the buffer char* c = strtok(temp, " "); // set the delimiters while(c != NULL) { if (i == 0) // i equal to 0 means we're parsing a number { i = 1; // next we'll parse a string, let indicate that sscanf(c, "%d", &d_out[di++]); } else // i must be 1 parsing a string { i = 0; // next we'll parse a number sprintf(s_out[si++], "%s", c); } c = strtok(NULL, " "); } printf("%d %s\n", d_out[di -1], s_out[si - 1]); // print what we've extracted } fclose(fh); return 0; } 

This will extract the contents from the file and store them in the corresponding arrays, then we will print them and return the original contents:

 $ ./a.out 10 aaa 20 bbb 30 ccc 
+2
source

Using:

 fgets (name, 100, stdin); 

100 is the maximum buffer length. You must adjust it according to your needs.

Using:

 scanf ("%[^\n]%*c", name); 

[] is a scan symbol. [^\n] says that although the input is not a newline ( '\n' ), enter the input. Then, with %*c it reads the newline character from the input buffer (which cannot be read), and * indicates that this reading in the input file is discarded (assignment suppression), since you do not need it, and this new line in the buffer does not create any problems for the following inputs that you could make.

+1
source

Your problem can be solved with sscanf (with getline support), as shown below:

 #include <stdio.h> #include <stdlib.h> int main(void) { FILE *fp; char *line = NULL; size_t len = 0; ssize_t read; /* tokens bags */ char tok_str[255]; int tok_int; fp = fopen("./file.txt", "r"); if (fp == NULL) exit(EXIT_FAILURE); /* Reads the line from the stream. */ while ((read = getline(&line, &len, fp)) != -1) { /* Scans the character string pointed by line, according to given format. */ sscanf(line, "%d\t%s", &tok_int, tok_str); printf("%d-%s\n", tok_int, tok_str); } if (line) free(line); exit(EXIT_SUCCESS); } 

Or, even easier. You can use fscanf (with feof support) and replace the while loop shown above (along with some other redundant code cleanups) with the following:

  /* Tests the end-of-file indicator for the stream. */ while (!feof(fp)) { /* Scans input from the file stream pointer. */ fscanf(fp,"%d\t%s\n",&tok_int, tok_str); printf("%d-%s\n", tok_int, tok_str); } 

Assuming your file contains the following lines (where the format of one line is the number [tab] string [newline]):

 12 apple 17 frog 20 grass 

the output will be:

 12-apple 17-frog 20-grass 
+1
source

The problem is that you are reading the file twice. First with fgets and then with scanf . You probably won't get errors from the compiler when using scanf , but you should get warnings, because you are using line for the format string, and the rest of the arguments are not formatted. It would also be obvious if you checked the return value from scanf , as it returns the number of items successfully scanned. Your call will most likely return zero (or minus one when you press the end of the file).

Instead, you should use sscanf to parse the line you are reading with fgets .

See this link for different scanf options.

0
source

Source: https://habr.com/ru/post/1500256/


All Articles