Parsing file to struct in C [duplicate] - c

This question already has an answer here:
fscanf with colon (:) delimited data
(1 answer)
Closed 7 years ago.
I have a file with questions and answers formatted like this:
1;Which US state is famous for Disneyland and the film industry?;California;Washington;Florida;
The number(which is 1 in this case) tells us how many questions the file contains.
I have a struct:
typedef struct{
char answer1[30];
char answer2[30];
char answer3[30];
char question[30];
}Questions;
I'll use a loop to scan in the text to the struct, something like this:
Questions q;
for(int i = 0; i < number;i++){
fscanf(file, ";%s; %s; %s; %s;", q.question, q.anwswer1, q.answer2, q.answer3);
}
The problem is that the question and answers in the file is separated with ";", how can I scan in the values in the file to the struct?

Take the following steps for each line of input:
use fgets with a large enough buffer to read a line from the input file. Check for a NULL return value to detect end of file.
parse the line with strchr, strtok or by testing for ';' explicitly with a for loop.
for each element, change the ';' separator to a '\0' and use strdup() to make a copy of the field value and store the pointer to the corresponding member of your structure.
use the Question structure for what it is needed, and free the pointers when it is no longer needed,
repeat for the next line.

Related

Unusual character when writing to file [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I've created a struct with 2 char[] and one int. I created an array of this struct and scanfed several inputs to store data into the array. Then I used fprintf to write this data to the file. But when I open the file I get û before every new record. Idk why is it happening.
Here's the relevant code:
FILE *outputFile=fopen("1021.txt","ab");
int tickets=0,i=1;
struct air s[30];
printf("\nEnter Number of tickets:");
scanf("%d",&tickets);
for (i=1;i<=tickets;i++)
{
printf("\nEnter the name\t");
scanf("%s",&s[i].name);
printf("\nEnter the phone number\t");
scanf("%s",&s[i].phoneNo);
printf("\n Enter the address\t");
scanf("%s",&s[i].address);
printf("Your ticket is confirmed\t");
getch();
}
for (i=0;i<=tickets;i++)
{
printf("%s", s[i].name);
printf("%s", s[i].phoneNo);
printf("%s", s[i].address);
fprintf(outputFile,"%s",s[i].name);
fprintf(outputFile,"%s",s[i].phoneNo);
fprintf(outputFile,"%s",s[i].address);
}
Here's what I get in the file:
ûdalla03332228458dallaÈfsÇûÿÿÿÿàrancho03312041265dallabancho
Where are those unusual characters coming from?
Your input loop is
for (i=1;i<=tickets;i++)
but the output loop is
for (i=0;i<=tickets;i++)
So you are writing data to file from element [0] that you have no data entered for. That is why it is junk.
In C, arrays are indexed from [0], and neither of those loops is right. Please change both of them to
for (i = 0; i < tickets; i++)
There are other problems in the code too, but this addresses the immediate "uninitialised data" problem.
Edit: some other problems.
You opened the file in "binary" mode, but you are using it as a text file. I believe the distinction is only necessary in Windows.
FILE *outputFile=fopen("1021.txt", "at"); // change to "t"
The string address passed to scanf should not contain an & address-of (unlike an int). Just pass the array - it decays to the required pointer.
scanf("%s", s[i].name); // removed `&`
As you have not written any newline to file to demark your string data, when you read the data back in, you will not know where each ends and the next begins. So for example, add the newline like this
fprintf(outputFile, "%s\n", s[i].name); // added \n
You say one member is an int presumably the phone number, but you are inputting as a string. Yet it is a bad idea to store phone numbers as integers, because a) thay might contain a character such as '+' or b) may start with a leading 0 and that will be lost when you store as int. So change the struct member phoneNo to be a char array of adequate length.
The scanf format specifier %s will stop at the first whitespace it meets, so the input statements will be better as this, which will only stop when it finds a newline or hits the length limit:
int res = scanf("%29[^\n]", s[i].name);
where the array length defined was [30] (you did not show the struct). Alternatively you could research the use of fgets().
Finally, you should check the return value of the functions you are calling to see if they were successful. fopen will tell you if the file opened correctly. scanf will tell you the number of entries it scanned, and fgets tells you if it was successful too.

I have a filename ABCD_81018293.txt. I try sscanf to get ABCD as text and the digits as an int [duplicate]

This question already has answers here:
Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer
(5 answers)
Closed 6 years ago.
One of the many forms I have tried is
char *text, ebuf[32];
int *num;
strncpy (ebuf,tfp->d_name,strlen(tfp->d_name));
sscanf (ebuf, "%s_%i.txt", text, num);
I started originally with tfp->d_name in place of the ebuf hack, with the same results: segment faults. I understood from the man page that perhaps the %s should be %4c (text string has 4 characters - but not always). Anyway %4c or 4%c didn't make any difference.
Thanks to all who responded. Your clarifications - especially WhozCraig's "better man page" - put me on the right track.
The initialization issue was not my major problem, it was the syntax of the sscanf. For my program, once initialization was out of the way, the single line I really needed was:
sscanf (tfp->d_name, "%[^_]_%i", &text[0], &num);
Your pointer are not inizialize, so are pointing to nothing consistent.
You can allocate space for them using malloc, like:
char *text = malloc(max_len);
int *num = malloc(sizeof(int));
// ....
free(text);
free(num);
As you can see mallocated memory must be freed to release the allocated memory.
Otherwise you can use a simple variable and an array to store your c-string
char text[max_len];
int num;
// ...
sscanf (ebuf, "%s_%i.txt", text, &num);
Take a look at this SO question to understand how you can manage to trigger a '_' as string delimiter.
So, as BLUEPIXY commented you:
sscanf(ebuf, "%[^_]_%i.", text, &num);
Last thing, you can avoid the strncpy, and sscanf directly to tfp->d_name
sscanf(tfp->d_name, "%[^_]_%i.", text, &num);
This also avoid the "explosion" of sscanf due to the no null terminated ebuf string: You should use strlen(tfp->d_name)+1 as third parameter of your strncpy to copy to ebuf the null terminator too.
As strlen Man says:
DESCRIPTION
The strlen() function calculates the length of the string pointed to
by s, excluding the terminating null byte ('\0').
emphasis mine

Sprintf function + order arguments [duplicate]

This question already has answers here:
Can the input and output strings to sprintf() be the same?
(2 answers)
Closed 7 years ago.
I have two string ta and tb with certain value, then I use the function sprintf to concatenate the two both in the variable ta, when I write
sprintf(ta,"%s+%s",ta,tb);
I get the string 1+2. but I need store in ta the string 2+1 then I trying
sprintf(ta,"%s+%s",tb,ta);
but I get the string 2+2+2+2+. I don't understand why happens that, Could you help me please?. Below the complete code
int main() {
char ta[5];
char tb[5];
sprintf(ta,"%d",1);
sprintf(tb,"%d",2);
sprintf(ta,"%s+%s",ta,tb);
//sprintf(ta,"%s+%s",tb,ta); uncomment for the second case
printf("taid:%s",ta);
}
sprintf(ta,"%s+%s",ta,tb);
sprintf(ta,"%s+%s",tb,ta);
Both lines of calling sprintf have undefined behavior. You are trying to copy ta to ta itself.
C11 §7.21.6.6 The sprintf function
The sprintf function is equivalent to fprintf, except that the output is written into an array (specified by the argument s) rather than to a stream. A null character is written at the end of the characters written; it is not counted as part of the returned value. If copying takes place between objects that overlap, the behavior is undefined.

Inputting an arithmatic statement in c and return the value [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
(I am very bad at inputting/processing strings in C. Hope this question will teach me a lot.)
I am trying to make a function that will input an arithmatic string from stdin, e.g 23 + 45 * 6 - 5, and return the value.
There are multiple strings, entered one after another, and can be of any length and the operator precedence doesn't matter, i.e., it processes string sequentially.
The problems that I faced are :-
\n from previous string is also considered a string.So if I input 3 strings , it will actually be 6, 3 strings and 3 \n.
I used a char pointer and used char * input; scanf(" %s",input);, but in addition to above problem, I also get segmentation fault, which I guess is due to missing \0.
My question is forget what mess I did, what would you have done or what's the best way to handle string input in the above scenario. A dummy code is sufficient.Thanks.
What I was doing
#include <stdio.h>
int main()
{
int t; //no of test cases
char input;
scanf("%d",&t);
while(t--)
{
while((input=getchar())!='\n')
{
//use switch to identify char and follow appropriate action
printf("%c\n",input );
}
}
return 0;
}
As suggested by Joachim Pileborg, use fgets. Use a char array, instead of one char variable, to store the string.
char input[100];
fgets(input, sizeof(input), stdin);
The advantage of fgets over sscanf is that fgets can read spaces in your input.
It will include the end-of-line byte \n, so 3 strings will not turn into 6 strings.
As usual with fgets, there is an arbitrary limit on the length of the input. If the user inputs something longer than 98 bytes, the system cannot fit it all (plus end-of-line \n and end-of-string \0 bytes), and the program will receive truncated string.
If you cannot tolerate that, use getline (it's harder to use, so use fgets if in doubt).
After you scan your string in, check to see if it is a '\n', if it is just ignore processing it and move to the next one.
Or you could try:
char input[101];
scanf("%s\n", &input);
First of all. Your idea of writing an fomular expression analyzer as a first projekt is not a very good one. Start with a simpler project.
You get the sagmentation fault, because you try to read data (with the scanf()) into a not initialized pointer.
char *input;
will not allocate any memory for the string you want to read with scanf(). You have to use a buffer something like
char input[256];
and give the pointer to the buffer to scanf("%s",input) (oder for better understanding scanf("%s",&input[0]);
Anywhere, this buffer has only 255 chars to store and you must be aware, that if you enter more then 255 chars in the scanf() you will get an illegal memory access as well.
Claus

How to use read() and/or fgetc to get certain strings [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
Using fgetc() and/or read() how to i get the keys and the values from a file?
This is how it is written in the file:
<key1,val1><key2,val2><key3,val3>
And i need to put each key and value in a new array(to do linked-lists).
So, to insert in the file using '<' and '>' and ',' it's no problem. The problem is how to get them?
Any ideas?
Here's what I have.
FILE * file;
char* key;
char* value;
int c;//apparently I have to use an int
file=fopen("myfile.txt", "r");
c=fgetc(file);
while(c != EOF)
{
c=fgetc(file);
if(c == '<'){
for(int i=0; c != ','; i++)
{
key[i]=fgetc(file);
}
}
}
This is till the first comma. Now I lack a little of algorithm conception. Help please.
Does it have to be fgetc and read ? .. Here is one way to do this :
while(!feof(your_file_name)){
bzero(line, sizeof(line)); // line is a char array ... make sure its of sufficiently large size
fgets(line,100,your_file_name); // I am reading 100 characters .. you can change that number as per your file accordingly
}
fclose(your_file_name);
sscanf(line,"<%d,%d><%d,%d><%d,%d>",&key1,&val1,&key2,&val2,&key3,&val3); // assuming keys and vals are ints
What you are doing in your code is reading the file character by character .. Why go through all that pain?
using fgets will read the entire file in one go ... then knowing the format of the file sscanf is immensely powerful tool to recover info from that
Ok so you posted in comments that keys and vals are strings .. so change the sscanf to this:
sscanf(line,"<%[^,]%[^>]<%[^,]%[^>]<%[^,]%[^>]",key1,val1,key2,val2,key3,val3);
Ok so let me explain
When dealing with the strings in sscanf you have to specify the delimiting character.
So this <%[^,] tells sscanf - start reading a string from after this < character and read it until you reach , character ...

Resources