Using "fscanf" in C How can Split two strings? - c

I want to a linked list in C using file operations. I want to get a line and split it and storage in structers. But I cant split two strings.
My File like this:
1#Emre#Dogan2#John#Smith3#Ashley#Thomasetc...
I want to read one line from file using fscanf.
fscanf(file,"%d#%s#%s",&number,name,surmane);
But the result is
Number : 1Name : Emre#Dogan
How can get rid of that # element in the name and split it to name and surname;

#include <stdio.h>
#include <string.h>
int main(void) {
FILE *fptr;
fptr = fopen("Input.txt", "r");
int number;
char *name;
char *surname;
char line_data[1024];
fgets(line_data, 1024, fptr);
number = atoi(strtok(line_data, "#"));
name = strtok(NULL, "#");
surname = strtok(NULL, "#");
printf("%d %s %s", number, name, surname);
}
Output:
1 Emre Dogan
EDIT:
Coverted the variable "number" from string to integer.

It's better to read a full line using fgets(), then parsing that line. This is more robust, using fscanf() directly on the input stream can be confusing due to the way fscanf() skips whitespace.
So, you could do:
char line[1024];
if(fgets(line, sizeof line, file) != NULL)
{
int age;
char name[256], surname[256];
if(sscanf(line, "%d#%255[^#]#%255s", &age, name, surname) == 3)
{
printf("it seems %s %s is %d years old\n", name, surname, age);
}
}
This uses the %[] format specifier to avoid including the # separator in the parsed strings. I think this is cleaner than strtok(), which is a scary function best avoided.

Related

Trying to fscanf multiple values (3 strings + integer) in a single line

I need to scan 3 strings and an integer from an already existing file, and save them each as an element in an array of structures. The file is formatted as such:
string1 string2 integer string3
string1 string2 integer string3
... and so on.
when fscanf-ing for them, it correctly scans string1, the integer, and string3. However, string2 always appears to create an error when scanning it, and when any of the string2's are printed, they are either cut off short, or have some odd ASCII symbol, like a question mark in a box; it also sometimes triggers the system "bell" sound.
I've tested collecting the strings through fscanf for each different one, and it is only the second one that ever messes up.
A stripped-down version of my code, highlighting the issue
struct carinfo
{
char name[10];
char make[15];
int number;
char color[10];
}car[4];
filepointer = fopen("file.txt", "r");
while(!feof(filepointer))
{
for(i=0;i<4;i++)
{
fscanf(filepointer, "%s %s %d %s", &car[i].name[10],
&car[i].make[15], &car[i].number, &car[i].color[10]);
printf("%s\n", &car[i].make[15]);
}
}
my expected result is that the second string will scan properly, and be stored in its entirety to its element in the array of structures; instead, the value is usually cut off (at around 2-3 characters instead of 15) and contain weird ASCII symbols.
Changing fscanf() function to this, will solve your issue.
Code
fscanf(filepointer, "%s %s %d %s", car[i].name,
car[i].make, &car[i].number, car[i].color);
You can find true way of using fscanf() in cplusplus.com:
char str [80];
FILE * pFile;
pFile = fopen ("myfile.txt","w+");
fscanf (pFile, "%s", str);
But as chris-dodd stated at comment section using feof(filepointer) inside while loop not correct.
This code below i correct it by using fscanf() return value.
I obtain this way in a stack overflow answer by lio
Complete version of your program
main.c
#include <stdio.h>
struct carinfo
{
char name[10];
char make[15];
int number;
char color[10];
}car[4];
int main(){
int i=0;
FILE* filepointer = fopen("file.txt", "r");
if(!filepointer){
printf("can't open file\n");
}
int ret=0;
do {
for(i=0;i<4;i++){
ret=fscanf(filepointer, "%s %s %d %s", &car[i].name,
&car[i].make, &car[i].number, &car[i].color);
printf("%s\n", &car[i].make);
}
} while (ret != EOF);
return 0;
}
file.txt
salam beshoma 10 daram
kee innak 15 inomikhonid!

Two words in a string from text file

I'm trying to get two words in a string and I don't know how I can do it. I tried but if in a text file I have 'name Penny Marie' it gives me :name Penny. How can I get Penny Marie in s1? Thank you
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("Hello world!\n");
char s[50];
char s1[20];
FILE* fp = fopen("file.txt", "rt");
if (fp == NULL)
return 0;
fscanf(fp,"%s %s",s,s1);
{
printf("%s\n",s);
printf("%s",s1);
}
fclose(fp);
return 0;
}
Change the fscanf format, just tell it to not stop reading until new line:
fscanf(fp,"%s %[^\n]s",s,s1);
You shall use fgets.
Or you can try to do this :
fscanf(fp,"%s %s %s", s0, s, s1);
{
printf("%s\n",s);
printf("%s",s1);
}
and declare s0 as a void*
The other answers address adjustments to your fscanf call specific to your stated need. (Although fscanf() is not generally the best way to do what you are asking.) Your question is specific about getting 2 words, Penny & Marie, from a line in a file that contains: name Penny Marie. And as asked in comments, what if the file contains more than 1 line that needs to be parsed, or the name strings contain a variable number of names. Generally, the following functions and techniques are more suitable and are more commonly used to read content from a file and parse its content into strings:
fopen() and its arguments.
fgets()
strtok() (or strtok_r())
How to determine count of lines in a file (useful for creating an array of strings)
How to read lines of file into array of strings.
Deploying these techniques and functions can be adapted in many ways to parse content from files. To illustrate, a small example using these techniques is implemented below that will handle your stated needs, including multiple lines per file and variable numbers of names in each line.
Given File: names.txt in local directory:
name Penny Marie
name Jerry Smith
name Anthony James
name William Begoin
name Billy Jay Smith
name Jill Garner
name Cyndi Elm
name Bill Jones
name Ella Fitz Bella Jay
name Jerry
The following reads a file to characterize its contents in terms of number of lines, and longest line, creates an array of strings then populates each string in the array with names in the file, regardless the number of parts of the name.
int main(void)
{
// get count of lines in file:
int longest=0, i;
int count = count_of_lines(".\\names.txt", &longest);
// create array of strings with information from above
char names[count][longest+2]; // +2 - newline and NULL
char temp[longest+2];
char *tok;
FILE *fp = fopen(".\\names.txt", "r");
if(fp)
{
for(i=0;i<count;i++)
{
if(fgets(temp, longest+2, fp))// read next line
{
tok = strtok(temp, " \n"); // throw away "name" and space
if(tok)
{
tok = strtok(NULL, " \n");//capture first name of line.
if(tok)
{
strcpy(names[i], tok); // write first name element to string.
tok = strtok(NULL, " \n");
while(tok) // continue until all name elements in line are read
{ //concatenate remaining name elements
strcat(names[i], " ");// add space between name elements
strcat(names[i], tok);// next name element
tok = strtok(NULL, " \n");
}
}
}
}
}
}
return 0;
}
// returns count, and passes back longest
int count_of_lines(char *filename, int *longest)
{
int count = 0;
int len=0, lenKeep=0;
int c;
FILE *fp = fopen(filename, "r");
if(fp)
{
c = getc(fp);
while(c != EOF)
{
if(c != '\n')
{
len++;
}
else
{
lenKeep = (len < lenKeep) ? lenKeep : len;
len = 0;
count++;
}
c = getc(fp);
}
fclose(fp);
*longest = lenKeep;
}
return count;
}
Change your fscanf line to fscanf(fp, "%s %s %s", s, s1, s2).
Then you can printf your s1 and s2 variables to get "Penny" and "Marie".
Try the function fgets
fp = fopen("file.txt" , "r");
if(fp == NULL) {
perror("Error opening file");
return(-1);
}
if( fgets (str, 60, fp)!=NULL ) {
/* writing content to stdout */
puts(str);
}
fclose(fp);
In the above piece of code it will write out the content with the maximum of 60 characters. You can make that part dynamic with str(len) if I'm not mistaken.

After reading from text file, results are displayed incorrectly

I've written a program that reads four variables (three strings and one character) every line from a text file. But when I display the variables, an unexpected character pops up at the end of each line. (I've ensured that the lengths of the variables are large enough).
Why is this? (Overflowing buffers, again?) And how do I fix this?
Text file contents:
M0001 Cool Name F 123-456789
M0002 Name Cool M 987-654321
Code:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *text;
char id[6], name[101], gender, contact[13];
text = fopen("test.txt", "r");
while (fscanf(text, "%s %[^\n]s %c %s\n", id, name, &gender, contact) != EOF)
printf("%s %s %c %s\n", id, name, gender, contact);
fclose(text);
return 0;
}
The output I expect:
M0001 Cool Name F 123-456789
M0002 Name Cool M 987-654321
What I get instead:
M0001 Cool Name F 123-456789 1⁄4
M0002 Name Cool M 987-654321 1⁄4
in the call to fscanf(), the format string: "%s %[^\n]s %c %s\n" is not correct.
the '[^\n]' will read to the end of the line (which will overflow the input buffer: `name'. Then the next char is NOT an 's' because the next character is the newline.
should compare the returned value to 4, not EOF
the input/format specifiers '%[...]' and '%s' have no problem overflowing the input buffer, so should ALWAYS have a MAX_CHARACTERS modifier that is one less than the length of the input buffer (those format specifiers always append a NUL byte to the input
The following proposed code:
cleanly compiles
documents why each header file is included
performs the desired functionality
splits the 'name' into 'firstname' and 'lastname' for easier handling and to match the format of the input data
properly checks the returned value from fscanf()
properly checks for any error from fopen() and if an error is returned, properly outputs the error message and the text indicating why the system thinks the function failed to stderr
uses an appropriate format string for the calls to fscanf() and printf()
replaces 'magic' numbers with meaningful names via a enum statement
And now the proposed code:
#include <stdio.h> // fopen(), fclose(), fscanf(), perror(), printf()
#include <stdlib.h> // exit(), EXIT_FAILURE
enum{
MAX_ID_LEN = 6,
MAX_NAME_LEN = 20,
MAX_CONTACT_LEN = 13
};
int main( void )
{
char id[ MAX_ID_LEN ];
char firstname[ MAX_NAME_LEN ];
char lastname[ MAX_NAME_LEN ];
char gender;
char contact[ MAX_CONTACT_LEN ];
FILE *text = fopen("test.txt", "r");
if( !text )
{
perror( "fopen to read 'test.txt' failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
while (5 == fscanf(text, "%5s %19s %19s %c %12s",
id, firstname, lastname, &gender, contact) )
{
printf("%s %s %s %c %s\n",
id, firstname, lastname, gender, contact);
}
fclose(text);
return 0;
}
%[^\n]s eats up everything from that point on and puts it in name. So only id and name are filled. gender and contact have 'random' contents coming from the program stack (as they are not initialized).
By accident the your stack had 1/4 in gender + contact.
On my machine, the program crashes.
As the number of space-delimited words in your name apparently is variable, you can only use %[^\n]s to grab "as much as possible" – but that will also eat up any and all following relevant data. A quick solution would be to re-design the input format and place the name at the very end; then, your fscanf argument would be:
"%s %c %s %s\n", id, &gender, contact, name
Alternatively, rewrite the code to use less fscanf and more 'manual' parsing:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main (void)
{
FILE *text;
char id[6], name[101], gender, contact[13];
char *lookback;
int result;
unsigned int line_number = 0;
text = fopen ("test.txt", "r");
if (text == NULL)
{
printf ("file not found!\n");
return EXIT_FAILURE;
}
do
{
result = fscanf(text, "%s %[^\n]s\n", id, name);
line_number++;
if (result == EOF)
break;
if (result != 2)
{
printf ("error in data file on line %u (expected at least 2 items)\n", line_number);
break;
}
/* at this point, 'name' also contains 'gender' and 'contact' */
lookback = strrchr (name, ' ');
if (lookback == NULL || strlen(lookback+1) > 12)
{
printf ("error in data file on line %u (expected 'contact')\n", line_number);
break;
}
/* lookback+1 because lookback itself points to the space */
strcpy (contact, lookback+1);
/* cut off at lookback */
*lookback = 0;
lookback = strrchr (name, ' ');
if (lookback == NULL || strlen(lookback+1) != 1)
{
printf ("error in data file on line %u (expected 'gender')\n", line_number);
break;
}
/* lookback now points to the space before the gender */
gender = toupper(lookback[1]);
if (gender != 'F' && gender != 'M')
{
printf ("error in data file on line %u (expected 'M' or 'F')\n", line_number);
break;
}
/* cut off again at lookback; now name is complete */
*lookback = 0;
printf ("%s %s %c %s\n", id, name, gender, contact);
} while (1);
fclose(text);
return EXIT_SUCCESS;
}
This method does have a couple of associated drawbacks. One of the perks of scanf is that it normalizes whitespace; multiple spaces and tabs (or even returns) will silently be translated to a single space before scanning. This code, on the other hand, explicitly checks for a single space character. If there is variation in the whitespace in your data file, you must account for that as well.
With the last two items 'manually' processed, you can opt to not use fscanf at all. You can read an entire line of text at once with fgets (which also has a line length check built in) and look for spaces using strchr and strrchr. To counter possible whitespace problems, search the line for tabs and double spaces and change these to a single space.

Split/Parse a String after reading a Text File?

I am trying to simply read in a basic text file, split each line into separate strings and rearrange/copy them onto a new text file. Is there any simple way to split and identify these strings to be added to a new file at the end of processing the lines?
My code so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *pFileCust
fPointer = fopen("Athletes.txt", "r");
char singleLine[150];
while (!feof(pFileCust)){
fscanf(singleLine, 150);
int id, name, sport;
fprintf(%d[0,6], %s[8,15], %s[16,22], id, name, sport);
}
fclose(fPointer);
return 0;
}
Example Text File to be read into the program:
88888 John Doe Tennis
99999 Jane Smith Softball
Example Output that I am trying to achieve.
Tennis 88888 John Doe
Softball 99999 Jane Smith
Each line in your file corresponds to a record. Each series of consecutive non-whitespace characters corresponds to a field in the current record. Accordingly,
/* getrecord: read next record on fp */
char *getrecord(FILE *fp)
{
assert(fp);
char *line = malloc(MAXLINE);
if (line != NULL)
if (fgets(line, MAXLINE, fp) != NULL)
return line;
return NULL;
}
/* getfield: read next field in record */
char *getfield(const char *record, int *pos)
{
assert(record && pos);
char *record;
int ret;
if ((record = malloc(MAXRECORD)) != NULL) {
ret = sscanf(record + *pos, "%s", record);
if (ret == 1)
return record;
}
return NULL;
}
While each function does not appear to do much work, separating your business logic from record/field reading has real benefits. It allows extensibility (for example you can add error handling to these routines). You can also make more sense of your code. Now you can write your main function which will use this pair of calls.
Here is a simple adaptation of your code that (a) compiles, and (b) generates the output that you desire.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *pFileCust = fopen("Athletes.txt", "r");
char first_name[100], last_name[100], sport[100];
int id;
while (fscanf(pFileCust, "%d %s %s %s", &id, first_name, last_name, sport) != EOF) {
printf("%s %d %s %s\n", sport, id, first_name, last_name);
}
fclose(pFileCust);
return 0;
}
One of the key things your app was missing was anything assigning values to your variables; your fscanf was not doing anything (if it even compiled). fscanf is not a very GOOD way to parse text, it's not very robust. But for the principle of understanding how variables are assigned, please look carefully at that, and in particular understand why the id has an ampersand in front of it. Also, make sure you understand why I used both a first name and a last name.

Reading a data file and storing into array of structures

I'm attempting to read a data file and to store the information into an array of course structures (or an array of pointers to course structures). This assignment requires maintaining a database using an array of pointers to the student structures.
I'm getting a segmentation fault when I attempt to scan the data file into the array. How can I properly store the information from the file into the array?
#define SIZE 30
#define fieldLength 300
#define diskFile "diskFile.dat"
#define courseFile "course.dat"
struct student
{
char name[fieldLength];
int age[fieldLength];
char course1[fieldLength];
char course2[fieldLength];
char remarks[fieldLength];
}*sp[SIZE];
struct course
{
char name[fieldLength];
char number[fieldLength];
char instructor[fieldLength];
char date[fieldLength];
char starting[fieldLength];
char ending[fieldLength];
char location[fieldLength];
};
int main(int argc, char *argv[])
{
int i, count;
struct course course_arr[SIZE]; // an array of ten structs
FILE * in; /*FILE pointer to do the stream IO*/
in = fopen(courseFile, "r+");
count = 0;
while ((fscanf(in, "%s %s %s %s %s %s %s",
&course_arr[count].name,
&course_arr[count].number,
&course_arr[count].instructor,
&course_arr[count].date,
&course_arr[count].starting,
&course_arr[count].ending,
&course_arr[count].location)) != EOF)
{
count++;
}
/* print the menu */
printf("\n-----------------------------------------------------------------\n");
printf("|\t%-20s","(N)ew record");
printf("%-20s","(U)pdate record");
printf("Swa(p) records\t|\n");
printf("|\t%-20s","(S)ort database");
printf("%-20s","(C)lear database");
printf("(D)isplay db\t|\n");
printf("|\t%-20s","(L)oad disk");
printf("%-20s","(W)rite disk");
printf("(E)mpty disk\t|\n");
printf("|\t%-20s", "(V)iew courses");
printf("%-20s","(R)emove record");
printf("(Q)uit \t|\n");
printf("-----------------------------------------------------------------\n");
printf("choose one: ");
Routine fscanf never returns EOF.
Test fscanf to be less than the number of expected fields:
count = 0;
while((fscanf(in, "%s %s %s %s %s %s %s", &course_arr[count].name, &course_arr[count].number, &course_arr[count].instructor, &course_arr[count].date, &course_arr[count].starting, &course_arr[count].ending, &course_arr[count].location)) < 7){
count++;
}
i think that it is better to work with
while(getline(string_variable,,)!=EOF).(look on the net on which argumentsto put in the getline)
Then work with the string_variable. Look at the format that the data is stored into the txt file. eg: name(blank)number(blank)instructor(blank)date(blank)starting(blank)endinglocation
Start looking for blanks in the string_variable. when you see the first blank copy the substring from position 1 to position blank-1 to the course_arr[count].name variable.then delete the substring from position 1 to position blank. Look again for the first blank and store the substring to course_arr[count].number and so on.
Sorry for my English hope u got the meaning
You should loose all the &s in the fscanf call. The char arrays are already passed as pointers. If you'd used the -Wall option on gcc (or a similar option for any other compiler) it will warn you for this as well.
Have you checked the file what you are reading is present or not.
add bellow
in = fopen(courseFile, "r+");
if(in == NULL)
{
printf("exit");
exit(0);
}
I guess it might be the problem.

Resources