About reading strings from a file in C - c

I have to read a file that has defined pattern: it will allways have a "Letter (single char) Number Number Number String"
For example:
A 20 22 2340 HELLO WORLD
So i'm trying to put each thing in a separeted item of my list.
I know how to get the first char and the 3 numbers and put it into a new variable, but i don't know how to get only the final string. If i use fgets, it will get all the line and, if i use fscanf, it will get the frist "word", but it won't get anything after the space. How can i read only the string and store it into a new variable?
int a, b, c, x, k = 0;
FILE *file;
file = fopen("Test.txt", "r");
while (fgets(buffer, 100, file) != NULL){
sscanf(buffer, "%c %i %i %i ", &a, &b, &c, &x);
Events.Key = k;
Events.Event = a;
Events.Day = b;
Events.Month = c;
Events.Year = x;
Insertion(Events, Data); //call my function to insert in the list
k++;
}
In this code, i can get the value from (my previous example) A 20 22 2340, but, if i put another %s and a string in the sscanf, it will get only "HELLO" and, if i use fgets, it will get the whole line. How can i get the whole string, including the spaces?
Thanks

You can use the string set specifier %[] which stops scanning where you tell it. Note that fgets() retains the trailing newline so it is convenient to stop there, and filter it out.
char name[50];
if(sscanf(buffer, "%c %i %i %i %49[^\n]", &a, &b, &c, &x, name) != 5)
{
// handle error
}
printf("%s\n", name);
Note the type error for %c as commented.

Got it, guys, i used [^\n], i didn't know about that function, thanks!

Related

How to scanf one string, a pipe, and then another string all without any break/space in between?

The user will enter the configuration of the bus, like this
2
OO|XO
XX|XX
where
the number in the first line (let n) tells the number of rows, and
the following n lines show a pair of two seats
with a walkway in between denoted by |, a pipe.
A seat can either be occupied or empty. An empty seat is denoted by an O; an occupied one by an X.
char str1[3], str2[3];
I'm treating each pair of seats as a string,
char pipe;
and the pipe as a character.
I tried doing this:
scanf("%s %*c %s", str1, pipe, str2);
and this:
scanf("%s", str1);
pipe = getchar();
scanf("%s", str2);
but still no luck.
The question is: How to enter two/more characters/strings in one go without separating them with any kind of space or break?
scanf lets you specify any separator that you wish to use, including pipe. Since the pipe is always there, you don't need to scan it into your program, instead instructing scanf to skip it:
char a[3], b[3];
scanf("%2s|%2s", a, b);
printf("'%s' '%s'", a, b);
Demo.
First, read the property of %s conversion specifier. The input is delimited by a whitespace, not by a pipe |, at least not automatically.
The easiest workaround would be, to use a maximum field width, something like
scanf("%2s%*c%2s", str1, str2); // the * in %*<CS> indicates assignment suppression,
// you don't need a corresponding argument at all, and
// a wrong one will cause trouble
here, you don't need to modify the code if you wish to chose a different delimiter, it'll consider anything as a delimiter. If you want to enforce the use of |, you can write
scanf("%2s|%2s", str1, str2);
NOTE - never forget to check the return value of scanf() to ensure success.
There are 2 different ways to address your problem:
If the string length is fixed, you can just specify the maximum number of characters to read for %s and use this code:
char str1[3], str2[3];
if (scanf("%2s|%2s", str1, str2) == 2) {
/* read 2 characters into str1, a pipe and 1 or 2 characters into str2 */
}
If the string length is variable, such as on planes with different numbers of seats in some rows, you can use a scanset %[OX] and also specify the number of characters to read to prevent potential buffer overflow on unexpected input. Here is an example:
char str1[5], str2[5]; // handle up to 4 seats on each side */
if (scanf("%4[OX]|%4[OX]", str1, str2) == 2) {
/* read a group of 1 to 4 `X` or `O` into str1 and str2, separated by | */
}
You can add another conversion to further verify that the line has the expected format. Here is an example:
#include <stdio.h>
int main(void) {
char buf[128];
int i, n, c;
char left[3], right[3];
if (fgets(buf, sizeof buf, stdin) == NULL) {
fprintf(stderr, "invalid format, empty file\n");
return 1;
}
if (sscanf(buf, "%d %c", &n, &c) != 1 || n < 0) {
fprintf(stderr, "invalid format, expected positive number: %s\n", buf);
return 1;
}
for (i = 0; i < n; i++) {
if (fgets(buf, sizeof buf, stdin) == NULL) {
fprintf(stderr, "missing %d lines\n", n - i);
return 1;
}
if (sscanf(buf, "%2[XO]|%2[XO] %c", left, right, &c) != 2) {
fprintf(stderr, "invalid format: %s\n", buf);
return 1;
} else {
printf("row %d: %s | %s\n", i + 1 + (i >= 12), left, right);
}
}
return 0;
}

Reading float numbers from a file in a special manner

I'm trying to read numbers from the file in a 2D-Array, i have to skip the first row and first column, rest all have to save in an array, i've tried using sscanf, fscanf and even strtok() but failed miserably. So please help me to solve this issue.
Thanx in advance,
Link to the file
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[]){
FILE *f=fopen("Monthly_Rainfall_Himachal.txt","r");
float data[12][12];
int i,j;
char newLine[1000];
fgets(newLine,1000,f);
char* item,waste;
i=0;
while(1)//read file line by line
{
fscanf(f, "%s %f %f %f %f %f %f %f %f %f %f %f %f ", waste, &data[i][0], &data[i][1], &data[i][2], &data[i][3], &data[i][4], &data[i][5], &data[i][6], &data[i][7], &data[i][8], &data[i][9], &data[i][10], &data[i][11]);
i++;
if(feof(f))break;
}
fclose(f);
for(i=0 ;i<12 ;i++){
for(j=0 ;j<12 ;j++){
printf("%.1f\t",data[i][j]);
}
printf("\n");
}
return 0;
}
Problems:
You don't check if the fopen was successful in opening the file or not and blindly assume it did.
Check its return value:
if(f == NULL)
{
fputs("fopen failed! Exiting...\n", stderr);
return EXIT_FAILURE;
}
Instead of reading and storing the first line, you can just read and discard it using scanf:
scanf("%*[^\r\n]"); /* Discard everything until a \r or \n */
scanf("%*c"); /* Discard the \r or \n as well */
/* You might wanna use the following instead of `scanf("%*c")`
if there would be more than one \r or \n
int c;
while((c = getchar()) != '\n' && c != '\r' && c != EOF);
But note that the next fscanf first uses a `%s` which
discards leading whitespace characters already. So, the
`scanf("%*c");` or the while `getchar` loop is optional
*/
You have an unused character pointer item and a character variable waste. Both of these are unnecessary. So, remove them.
In the very long fscanf line, you first try to scan in a string into a character variable which invokes Undefined Behavior and things go haywire. You also need to check its return value to see if it was successful.
Replace that fscanf line with the following:
if(fscanf(f, "%*s") == EOF)
{
fputs("End Of File! Exiting...\n", stderr);
return EXIT_SUCCESS;
}
for(j = 0; j < 12; j++)
{
if(fscanf(f, "%f", &data[i][j]) != 1)
{
fputs("End Of File or bad input! Exiting...\n", stderr);
return EXIT_SUCCESS;
}
}
You assume the input is of a maximum of 12 lines, but if it contains more than 12 lines, your code will invoke Undefined Behavior due to an array overrun.
Check the value of i along with the feof to make sure it does not go beyond 11:
if(i >= 12 || feof(f))
Note: I did not test any of the above code. Please correct me if I've made a mistake. Thanks!

C - reading ints and chars into arrays from a file

I have a .txt file with values written in this format: LetterNumber, LetterNumber, LetterNumber etc (example: A1, C8, R43, A298, B4). I want to read the letters and the numbers into two separate arrays (example: array1 would be A C R A B; array2 would be 1 8 43 298 4). How can I make it happen?
At the moment I only figured out how to read all the values, both numbers and letters and the commas and everything, into one array of chars:
FILE *myfile;
myfile = fopen("input1.txt", "r");
char input[677]; //I know there are 676 characters in my .txt file
int i;
if (myfile == NULL) {
printf("Error Reading File\n");
exit (0);
}
for (i=0; i<677; i++) {
fscanf(myfile, "%c", &input[i]);
}
fclose(myfile);
But ideally I want two arrays: one containing only letters and one containing only numbers. Is it even possible?
I would appreciate any kind of help, even just a hint. Thank you!
Define another array for integers,
int inputD[677];
Then in for loop read one char, one integer and one space char at a time.
fscanf(myfile, " %c%d %*[,] ", &input[i], &inputD[i]);
I would actually define a struct to keep letter and number together; the data format strongly suggests that they have a close relation. Here is a program that exemplifies the idea.
The scanf format is somewhat tricky to get right (meaning as simple as possible, but no simpler). RoadRunner, for example, forgot to skip whitespace preceding the letter in his answer.
It helps that we have (I assume) only single letters. It is helpful to remember that all standard formats except %c skip whitespace. (Both parts of that sentence should be remembered.)
#include<stdio.h>
#define ARRLEN 10000
// Keep pairs of data together in one struct.
struct CharIntPair
{
char letter;
int number;
};
// test data. various space configurations
// char *data = " A1, B22 , C333,D4,E5 ,F6, Z12345";
void printParsedPairs(struct CharIntPair pairs[], int count)
{
printf("%d pairs:\n", count);
for(int i = 0; i<count; i++)
{
printf("Pair %6d. Letter: %-2c, number: %11d\n", i, pairs[i].letter, pairs[i].number);
}
}
int main()
{
setbuf(stdout, NULL);
setbuf(stdin, NULL);
// For the parsing results
struct CharIntPair pairs[ARRLEN];
//char dummy [80];
int parsedPairCount = 0;
for(parsedPairCount=0; parsedPairCount<ARRLEN; parsedPairCount++)
{
// The format explained>
// -- " ": skips any optional whitespace
// -- "%c": reads the next single character
// -- "%d": expects and reads a number after optional whitespace
// (the %d format, like all standard formats except %c,
// skips whitespace).
// -- " ": reads and discards optional whitespace
// -- ",": expects, reads and discards a comma.
// The position after this scanf returns with 2 will be
// before optional whitespace and the next letter-number pair.
int numRead
= scanf(" %c%d ,",
&pairs[parsedPairCount].letter,
&pairs[parsedPairCount].number);
//printf("scanf returned %d\n", numRead);
//printf("dummy was ->%s<-\n", dummy);
if(numRead < 0) // IO error or, more likely, EOF. Inspect errno to tell.
{
printf("scanf returned %d\n", numRead);
break;
}
else if(numRead == 0)
{
printf("scanf returned %d\n", numRead);
printf("Data format problem: No character? How weird is that...\n");
break;
}
else if(numRead == 1)
{
printf("scanf returned %d\n", numRead);
printf("Data format problem: No number after first non-whitespace character ->%c<- (ASCII %d).\n",
pairs[parsedPairCount].letter, (int)pairs[parsedPairCount].letter);
break;
}
// It's 2; we have parsed a pair.
else
{
printf("Parsed pair %6d. Letter: %-2c, number: %11d\n", parsedPairCount,
pairs[parsedPairCount].letter, pairs[parsedPairCount].number);
}
}
printf("parsed pair count: %d\n", parsedPairCount);
printParsedPairs(pairs, parsedPairCount);
}
I was struggling a bit with my cygwin environment with bash and mintty on a Windows 8. The %c would sometimes encounter a newline (ASCII 10) which should be eaten by the preceding whitespace-eating space, derailing the parsing. (More robust parsing would, after an error, try to read char by char until the next comma is encountered, and try to recover from there.)
This happened when I typed Ctr-D (or, I think, also Ctr-Z in a console window) in an attempt to signal EOF; the following enter key stroke would cause a newline to "reach" the %c. Of course text I/O in a POSIX emulation on a Windows system is tricky; I must assume that somewhere between translating CR-NL sequences back and forth this bug slips in. On a linux system via ssh/putty it works as expected.
You basically just have to create one char array and one int array, then use fscanf to read the values from the file stream.
For simplicity, using a while loop in this case makes the job easier, as you can read the 2 values returned from fscanf until EOF.
Something like this is the right idea:
#include <stdio.h>
#include <stdlib.h>
// Wasn't really sure what the buffer size should be, it's up to you.
#define MAXSIZE 677
int
main(void) {
FILE *myFile;
char letters[MAXSIZE];
int numbers[MAXSIZE], count = 0, i;
myFile = fopen("input1.txt", "r");
if (myFile == NULL) {
fprintf(stderr, "%s\n", "Error reading file\n");
exit(EXIT_FAILURE);
}
while (fscanf(myFile, " %c%d ,", &letters[count], &numbers[count]) == 2) {
count++;
}
for (i = 0; i < count; i++) {
printf("%c%d ", letters[i], numbers[i]);
}
printf("\n");
fclose(myFile);
return 0;
}

fgets give me random big number

This is my code, I don't know how to use fgets after scanf so I am using fgets in the 26th line too but every time I use it, it give me big number(ex.2752100) but I write 2.
Why is it doing it?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
char veta[100];
int line = 1;//tell what line it is on
int found = 0;
char a[100];//put the characters of the line into here
char b[100];
char linesearch[10];//the line you are looking for
FILE *file;//the file pointer
file = fopen("text.txt","r");//point the file
if (file == NULL)
{
printf("file does not exist or doesn't work\n");
return 0;
}
printf("Ahoj, naucim te psat snadno a rychle! \n");
printf("Vyber si uroven slozitosti od 1 do 10:\n");
//scanf("%d", &linesearch);
fgets(linesearch,10,stdin);
printf("\nHledam uroven %d ...\n\n",linesearch);
EDIT:
i have another problem:
while(fgets(a,100,file))
{
if(x == line)
{
found = 1;
printf("level %d found,level %d say: %s",x,x,a);
}
else
printf("reading level: %d\n",line );
line++;
}
printf("\nwrite your string as fast as you can!!");
fgets(veta,40,stdin);
if (strcmp(veta,a) == 0)
{
printf("\nwell done!!!!\n");
}
else
{
printf("\nwrong!!!!\n");
printf("%s", a);
printf("%s", veta);
}
i have small senteces(ex I like my mum and she likes me,etc) i want to compare my text with text from file and get answer if I write it well or not. Bonus points if it tell me how many mistakes i did it will be powerful!.
The fgets() function reads character data from the input. To convert this character data to an integer, use atoi() or a similar function.
fgets(linesearch, 10, stdin);
int x = atoi(linesearch);
printf("\nHledam uroven %d ...\n\n",x);
Your printf statement is printing out the address of the linesearch array, which will seem like a random big number.
If you want to read from stdin, into a char array, using scanf() and then print as an int:
scanf("%s", linesearch); // e.g. reads 1234 into array linesearch[].
printf(" %s ...\n\n",linesearch); // Prints string in array linesearch[].
printf(" %p ...\n\n",linesearch); // Prints base address of linesearch[].
int iNum = atoi(linesearch); // Converts string "1234" to number 1234.
printf(" %d ...\n\n",iNum); // Prints the converted int.
iNum++; // Can perform arithmetic on this converted int.
You are getting a big number from printf because you used %d in the format. The number is the memory address of your character array. To print the character array, update the format to %s.

how to read more than one word between double quotes from a file in C

i'm trying to read strings from a file and into a struct but when i reach strings with two or more words everything i seem to try does not work
data in file
"K300" "Keyboard" "US Generic" 150.00 50
"R576" "16-inch Rims" "Toyota Verossa" 800.00 48
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct partInfo {
char number[6];
char name[20];
char description[30];
double price;
int qty;
}Part;
int main() {
char num[6], name[20], desc[30];
int i=0;
int q;
double p;
char ch;
FILE * in = fopen("input.txt", "r");
Part part1;
fscanf(in, " %[^ ]s", &num);
printf("%s\n", num);
fscanf(in, " %[^ ]s", &name);
printf("%s\n", name);
fscanf(in, " %[^ ]s", &desc); //right here only copy "US and not the Generic"
printf("%s\n", desc);
strcpy(part1.number, num);
strcpy(part1.name, name);
strcpy(part1.description, desc);
fclose(in);
return 0;
}
however when i try to use
fscanf(in, " %[^\n]s", &desc);
it copies the rest of the line
i've been stuck on this for two days can someone please help me
and also how to get rid of the double quotes if that is possible
i tried a different set of code for that and more errors arise :(
In scanf, the expression %[chars] reads the longest string that contains the characters (or character ranges) in the bracket. A caret as first character reverses this: %[^chars] reads the longest string that does not contain any of the characters. Hence, %[^ ] reads stuff up to the next space, and %[^\n] reads stuff up to the next new line.
In your case, where the string is delimited by double quotes, you should read the opening quote, then stuff up to the next quote and finally the closing quote:
res = fscanf(in, " \"%[^\"]\"", name);
This format starts with a space and so discards white space before the first quote. The format string looks ugly because the double quote itself is escaped. To illustrate, this is how the command would look like if your strings were delimited by single quotes.
res = fscanf(in, " '%[^']'", name);
This approach works only if your strings are always enclosed in quotes, even if they don't have spaces.
It is probably cleaner to read a whole line with fgets and then sscanf from that line to catch unmatched quotes. That way you could also scan the line several times - once for a string with quotes, a second time for an unquoted string, say - without accessing the disk more than once.
Edit: Corrected the format syntax, which containes a spurious s and updated the description of the bracket syntax for strings in the first paragraph.
Edit II: Because the OP seems to be confused about how fscanf works, here's a small example that reads parts from a file line by line:
#define MAX 10
#define MAXLINE 240
int main(int argc, char *argv[])
{
FILE *in;
int nline = 0;
Part part[MAX];
int npart = 0;
int res, i;
in = fopen(argv[1], "r"); // TODO: Error checking
for (;;) {
char buf[MAXLINE];
Part *p = &part[npart];
if (fgets(buf, MAXLINE, in) == NULL) break;
nline++;
res = sscanf(buf,
" \"%5[^\"]\" \"%19[^\"]\" \"%29[^\"]\" %lf %d",
p->number, p->name, p->description, &p->price, &p->qty);
if (res < 5) {
static const char *where[] = {
"number", "name", "description", "price", "quantity"
};
if (res < 0) res = 0;
fprintf(stderr,
"Error while reading %s in line %d.\n",
where[res], nline);
break;
}
npart++;
if (npart == MAX) break;
}
fclose(in);
// ... do domething with parts ...
return 0;
}
Here, the line is read in forst from the file. Then, that line (buf) is scanned for the required format. Of course, sscanf must be used instead of fscanf here. On error, a simple error message is printed. This message includes the line number and the field entry where reading went wrong, so the error can be located in the input file.
Note how the sscanf includes maximum field lengths to avoid overflowing the string buffers of the part. A scanning error occurs when the quoted string is too long. It would be nicer to have sscanf read all characters and only store the first 5, say, but that's not how sscanf works. Such a solution requires another approach, probably a custom scanning function.

Resources