fscanf doesn't recognise delimeters defined in format string ( - c

I'm trying to read user login data (username, password, some integer, security answer) from a file and store it in a linked list. The file validation.txt holds the data for all users, where each user has a line of its own holding all of the fields for that user in the format (no spaces):
user1_$_ password1 _$_42 _$_answer1
user2_$_ password2 _$_21 _$_answer2
The various fields are to be stored as members of a struct (named 'user') that comprises the linked list (each struct also has a member "next" which points to the next user in the list.
I trying to use fscanf to parse each line and save the info directly into the structs, but for some reason, the fscanf doesn't pick up on $ when it reaches them, and stores an entire line under the "username" member rather than just the string "user1". I have read loads online about the string format but can't figure this out. I played around trying to add whitespaces to the file and to the format string with many different outcomes that I didn't really understand why they are the way they are.. Based on what I read online the string should be read until a character present in the format string is reached, and it is then skipped over. This seems pretty straightforeward but why doesn't this work ?
My code:
user *loadUsers(){
user *Users, *currPtr;
FILE *fp = fopen("validation.txt", "r");
if(fp==NULL||feof(fp)!=0){
return NULL;
}
Users = (user *)malloc(sizeof(user));
currPtr = Users;
fscanf(fp, "%s_$_%s_$_%d_$_%s\n", currPtr->username, currPtr->password, &(currPtr->randomNum), currPtr->secAns);
while(feof(fp)==0){
currPtr->next = (user *)malloc(sizeof(user));
currPtr = currPtr->next;
fscanf(fp, "%s_$_%s_$_%d_$_%s\n", currPtr->username, currPtr->password, &(currPtr->randomNum), currPtr->secAns);
}
return Users;
}
Output:
When I iterate through my list after the call to this function and print just the username members of each struct, I get the whole line printed (username = user1_$_ password1 _$_42 _$_answer1 rather than just user1). Anyone know what's going on here ?

Never, ever, call *scanf() without checking the return value.
%s matches any sequence of non-whitespace characters, i.e. fscanf() keeps matching that first %s and does not even "see" the following underscore in the format string.
You could work with %[^_] to match everything not an underscore, but generally speaking you are better off reading whole lines of input with fgets() and then parse the input in memory using the various string functions. *scanf() is rather limited in its ability to recover from malformed input.

Related

Storing a string of inputs into a struct in C

was wondering how I would be able to store a user inputted string in the format "string,character,integer,integer"
into a struct.
For example storing "apple,c,5,10" into
typedef struct {
char item[80];
char letter;
int x,y;
}information;
information apple;
I am trying to avoid going through using scanf and a long piece of code to make the comma into a delimiter so wondering if there was any other way to quickly read from scanf and chucking this information into the struct
You can specify complex formats using scanf, like:
scanf("%79[^,],%c,%d,%d", apple.item, &apple.letter, &apple.x, &apple.y);
%79[^,] means scan anything that is not a comma character, up to 79 characters.
Note that this does no error handling if the user enters a poorly formatted string, like "aaa;b;1;2". For that, you'll need to write a lot more code. See strtok
You can use multiple format specifiers in the format string to scanf() to scan all the input at once, through a comma-seperated user input, like
int ret = -1;
if ((ret = scanf("%79[^,],%c,%d,%d", apple.item, &apple.letter, &apple.x, &apple.y)) != 4)
//always check the return value of scanf()
{
printf("scanf() failed\n");
//do something to avoid usage of the member variables of "apple"
}
However, I'll recommend the long way, like
read the line using fgets()
tokenize using strtok() and , as delimiter
use the token (or convert using strtol(), as required).
Much safe and robust.
Try to read using the func read() then just split the string using strtok()
Here's some references :
strtok : http://man7.org/linux/man-pages/man3/strtok.3.html
read : http://linux.die.net/man/2/read

C while loop until user enters "quit"

Here's my code:
1. User types in two names, with a space in between. This means that two strings need to be read. I.e. input:
John Doe.
The strings are then checked in a char-array. (works fine).
The while loop goes on until the user types "stop" - only "stop".
How can I make it to stop directly if "stop" is entered - without the need to check the second string?
The code:
while(bool==false)
{
scanf("%20s%20s", name1, name2);
if(strcmp(name1, "stop")==0)
{
break;
}
// but still the second name has to be entered
rest of code...
}
Thanks for any tips!
I suggest you use fgets to get the input, check for the "stop" string, and then use sscanf to parse the input.
You can put to use the regular expression character class support provided by scanf.
You could do:
scanf("%s%[^\n]s", name, temp);
Here, your first word is mandatory while second is optional.
When you input 2 words, your temp would have a leading space.
If you want to directly avoid it, you can do so by:
char *p = temp;
scanf("%s%[^\n]s", name, p++);
Here, you can later access your 2 words using name and p

Reading CR terminated keyword text file

I want to read a list of keywords from a (text) file and then add those in a CString array in C. The trouble is that, I am reading the file line by line, and the file contains one word in every line. I can successfully populate the array, but when I try to look up these keywords in another string, it returns false because I am guessing the keyword has \n at the end.
Another way I could read the file could be, to make the text file a comma separated file, and read one line and tokenize it. But then, I won't know how to read a line whose size can be VERY large, as the list of keyword is ever expanding.
Saad Rehman
If your problem is that a string may have a rogue newline at the end, you can use:
size_t len = strlen (mystring);
if (len > 0)
if (mystring[len-1] == '\n')
mystring[--len] = '\0';
Do this to mystring after you've read it in but before you use it.
It simply checks if the last character is a newline and, if so, replaces it with a string terminator.
The first check is to ensure you don't try this on an empty string where mystring[-1] would invoke the dreaded undefined behaviour.

Reading in data from a string in C (like scanf)

I've read in and stored a data file that I am processing into an array of char arrays, one char array for each line in the file and I now want to process the individual lines. I'm not however sure how to do this.
I read each line in like so:
/* Read the whole file into an array */
char read_lines[FILE_LENGTH][FILE_WIDTH];
for(i=0;i<FILE_LENGTH;i++) {
fscanf(data_file, "%[^\n]", read_lines[i]);
fscanf(data_file, "%[\n]", dump);
}
I need to read the data in each line which is formatted as %d\t%d\t%d\t%d\t%d and I'm not really sure how to read a specific variable into a scanf function. I know that fscanf() reads from a file and scanf() reads from user input, is there a function that reads from a variable?
I come from a python background and in python, I would just use the following code:
read_lines = open('file.txt').readlines()
for line in lines:
i = lines.index(line)
first[i], second[i], third[i], forth[i], fifth[i] = line.split('\t')
I really cannot see how to do the equivalent in C. I've done a fair bit of research but I couldn't find anything useful. Any help would be appreciated!
Thanks!
Perhaps check out sscanf. It is just like it's cousin scanf and fscanf but takes a string instead. Here is a snip from the above link.
The sscanf function accepts a string from which to read input, then, in a manner similar to printf and related functions, it accepts a template string and a series of related arguments. It tries to match the template string to the string from which it is reading input, using conversion specifier like those of printf.
You can use the strtok function [read the manpage] to split a string
e.g. http://www.gnu.org/s/libc/manual/html_node/Finding-Tokens-in-a-String.html

How to parse this input in C

Right now i am doing an assignment but find it very hard to parse the user input in C. Here is kind of input user will input.
INSERT Alice, 25 Norway Drive, Fitzerald, GA, 40204, 6000.60
Here INSERT is the command (to enter in link list)
Alice is a name
25 Norway Drive is an address
Fitzerald is a city
GA is a state
40204 is a zip code
6000.60 is a balance
How can I use scanf or any other method in C to properly take this as input? The biggest problem in front of me is how to ignore these "," and store these values in separate variables of appropriate data types.
Thanks everyone, i have solve the issue and here is the solution:
pch = strtok(NULL, ","); pch =
substr(pch, 2, strlen(pch)); //substr is my custom funcition and i believe you can tell by its name what it is doing.
strcpy(customer->streetAddress, pch);
Fast easy method:
Use fgets() to get the string from the user;
and strtok() to tokenize it.
Edit
After reading your comment:
Use strtok() with only the comma, and then remove trailing and leading spaces from the result.
Edit2
After a test run, I noticed you will get "INSERT Alice" as the first token. So, after all tokens have been extracted, run strtok() again, this time with a space, on the first token extracted. Or, find the space and somehow identify the command and the name from there.
If your input data format is fixed you can use something quick and dirty using [s]scanf().
With input of:
INSERT Alice, 25 Norway Drive, Fitzerald, GA, 40204, 6000.60
You might try, if reading from stdin:
char name[80], addr[80], city[80], state[80];
int zip;
double amt;
int res = scanf("INSERT %[^,], %[^,], %[^,], %[^,], %d, %f\n",
&name, &addr, &city, &state, &zip, &amt);
Should return the number of items matched (i.e. 6).
scanf() may be a bit tricky in this situation, assuming that different commands with different parameters can be used. I would probably use fgets() to read in the string first, followed by the use of strtok() to read the first token (the command). At that point you can either continue to use strtok() with "," as the delimiter to read the rest of the tokens in the string, or you could use a sscanf() on the rest of the string (now that you know the format that the rest of the input will be in). sscanf() is still going to be a pain due to the fact that it appears that an unspecified number of spaces would be allowed in the address and possibly town fields.

Resources