I have a text file that looks like this:
i 3755
i 3633
i 4435
i 1434
how would I go about reading this as an input, I've tried using fscanf, but it keeps on giving me a random character after the 'i'
for example output would look like
i% 3755
i5 3633
etc.
Here is what I've been trying:
int data = 0;
char command;
if(fptr==NULL)
printf("File Cannot Be Read");
fscanf(fptr,"%c %d\n", &command, &data);
printf("%c " , command);
printf("%d\n" , data);
fscanf(fptr,"%s %d\n", &command, &data);
printf("%c " , command);
printf("%d\n" , data);
fscanf(fptr,"%s %d\n", &command, &data);
printf("%s " , command);
printf("%d\n" , data);
none of them seem to work. Thanks for your help in advance!
edit: Heres the working code for anybody that was having the same problem:
int data = 0;
char command;
fptr = fopen(argv[1], "r");
if(fptr==NULL)
printf("File Cannot Be Read");
while(fscanf(fptr,"%c %d \n", &command, &data) == 2)
{
if(command == 'i')
{
printf("insert found\n");
}
if(command == 'd')
{
printf("delete found\n");
}
}
}
fscanf(fptr,"%c %d", command, &data);
should be:
fscanf(fptr,"%c %d", &command, &data);
getchar(); // consume the newline character that fscanf left.
Assuming you defined:
char command;
int data;
For simplicity, I would recommend you to, in a loop, read a line using fgets() and then use strtok() to get different 'strings' and then cast according to your parsing methodology. But Mike is right as well, you can use fscanf(fptr, "%c %d\n", &command, &data) to read. When you're using a string, you can ignore the usage of "&" before the variable name. But when its a character or an integer or a float.. you will need to use the address of operator("&")
at this line :
fscanf(fptr,"%c %d", command, &data);
you should give it a pointer to command. like this :
fscanf(fptr,"%c %d", &command, &data);
the next line can't work because the reading cursor is already at the end of the file.
This is incorrect and will result in a buffer overrun:
fscanf(fptr,"%s %d", &command, &data);
as command has only enough space for a single char but fscanf() with format specifier "%s" will read until next whitespace and then write a terminating null character into command. Use a char[] to read and restrict the number of chars to be read.
Note that the NULL check just prints an error message, it does not actually prevent use of a NULL file pointer.
To ensure that each line is of the correct format use fgets() to read a line and then use sscanf() to read the fields. If fscanf() is used to read directly from the file then these two lines:
i
3755
are treated identically to the single line:
i 3755
as a new-line character is also whitespace.
Example:
if (fptr)
{
char line[1024];
while (fgets(line, 1024, fptr))
{
char command;
int data;
if (2 == sscanf(line, "%c %d", &command, &data))
{
/* Use 'command' and 'data'. */
}
}
}
in your fscanf function you have to expect the return to line by adding space at the end of format. Like this
fscanf(fptr,"%c %d ", &command, &data);
The space character replaces return to new line, tabulation and spaces
BTW I see that you use %s to read a char &command and this is incorrect
fscanf(fptr,"%s %d\n", &command, &data);
you have to use this instead
fscanf(fptr,"%c %d ", &command, &data);
Related
I am using sscanf to read user input and save to several outputs. As far as my understanding goes, if I have sscanf(iput, %s %s %s %s, arr[0], arr[1], arr[2], arr[3]) I can have up to 4 items entered, but it does not require 4; meaning I could just put two and arr[2] ad arr[3] would have no value. However, I think I am not understanding something since later when I check the values of arr[2]/arr[3] they are not null, when I thought strings were just initialized with \0. Look at my code please and tell me what the if statement should be checking for I guess.
printf("Enter a command: ");
char input[20];
char line[5][20];
fgets(input, 20, stdin);
sscanf(input, "%s %s %s %s %s", line[0], line[1], line[2], line[3], line[4]);
....
else {
int status;
if(line[4] != NULL) {
char *args[6];
args[0] = line[0];
args[1] = line[1];
args[2] = line[2];
args[3] = line[3];
args[4] = line[4];
args[5] = NULL;
if ( fork() == 0 ) {
execv( args[0], args ); // child: call execv with the path and the args
}
else {
wait( &status );
}
Using the comment Jerry Jeremiah said, instead of changing the declaration to a pointer, I changed the line[x] in the if statement to a pointer and checked for NULL.
scanf will attempt to get everything you asked for. You ask for five, it tries to get five.
sscanf(input, "%19s %19s %19s %19s %19s", line[0], line[1], line[2], line[3], line[4]);
Without the specification, it will take as many chars as the user is inclined to submit, thus resulting in a buffer overflow. Bad idea.
I would accept one argument at a time, or take it all as one lump.
I am not able to flush stdin here, is there a way to flush it? If not then how to make getchar() to take a character as input from user, instead of a "\n" left by scanf() in the input buffer??
#include "stdio.h"
#include "stdlib.h"
int main(int argc,char*argv[]) {
FILE *fp;
char another='y';
struct emp {
char name[40];
int age;
float bs;
};
struct emp e;
if(argc!=2) {
printf("please write 1 target file name\n");
}
fp=fopen(argv[1],"wb");
if(fp==NULL) {
puts("cannot open file");
exit(1);
}
while(another=='y') {
printf("\nEnter name,age and basic salary");
scanf("%s %d %f",e.name,&e.age,&e.bs);
fwrite(&e,sizeof(e),1,fp);
printf("Add another record (Y/N)");
fflush(stdin);
another=getchar();
}
fclose(fp);
return 0;
}
EDIT: updated code, still not working properly
#include "stdio.h"
#include "stdlib.h"
int main(int argc,char*argv[]) {
FILE *fp;
char another='y';
struct emp {
char name[40];
int age;
float bs;
};
struct emp e;
unsigned int const BUF_SIZE = 1024;
char buf[BUF_SIZE];
if(argc!=2) {
printf("please write 1 target file name\n");
}
fp=fopen(argv[1],"wb");
if(fp==NULL) {
puts("cannot open file");
exit(1);
}
while(another=='y') {
printf("\nEnter name,age and basic salary : ");
fgets(buf, BUF_SIZE, stdin);
sscanf(buf, "%s %d %f", e.name, &e.age, &e.bs);
fwrite(&e,sizeof(e),1,fp);
printf("Add another record (Y/N)");
another=getchar();
}
fclose(fp);
return 0;
}
Output:
dev#dev-laptop:~/Documents/c++_prac/google_int_prac$ ./a.out emp.dat
Enter name,age and basic salary : deovrat 45 23
Add another record (Y/N)y
Enter name,age and basic salary : Add another record (Y/N)y
Enter name,age and basic salary : Add another record (Y/N)
fflush(stdin) is undefined behaviour(a). Instead, make scanf "eat" the newline:
scanf("%s %d %f\n", e.name, &e.age, &e.bs);
Everyone else makes a good point about scanf being a bad choice. Instead, you should use fgets and sscanf:
const unsigned int BUF_SIZE = 1024;
char buf[BUF_SIZE];
fgets(buf, BUF_SIZE, stdin);
sscanf(buf, "%s %d %f", e.name, &e.age, &e.bs);
(a) See, for example, C11 7.21.5.2 The fflush function:
int fflush(FILE *stream) - If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.
Update: You need to add another getchar() at the end of your loop to consume the '\n' that follows the Y/N. I don't think this is the best way to go, but it will make your code work as it stands now.
while(another=='y') {
printf("\nEnter name,age and basic salary : ");
fgets(buf, BUF_SIZE, stdin);
sscanf(buf, "%s %d %f", e.name, &e.age, &e.bs);
fwrite(&e,sizeof(e),1,fp);
printf("Add another record (Y/N)");
another=getchar();
getchar();
}
I would suggest reading the data you want to parse (up to and including the '\n') into a buffer and then parse it out using sscanf(). This way you consume the newline and you can perform other sanity checks on the data.
Use this instead of getchar():
char another[BUF_SIZE] = "y";
while( 'y' == another[0] )
{
printf( "\nEnter name,age and basic salary : " );
fgets( buf, BUF_SIZE, stdin );
sscanf( buf, "%s %d %f", e.name, &e.age, &e.bs );
fwrite( &e, sizeof(e) , 1, fp );
printf( "Add another record (Y/N)" );
fgets( another, BUF_SIZE, stdin );
}
It's not a good practice to use fflush( stdin ) as it has undefined behavior. Generally, functions like scanf() leaves trailing newlines in stdin. So, it is better to use functions that are "cleaner" than scanf(). You can replace your scanf() with a combination of fgets() and sscanf() and you can do away with fflush( stdin ).
I would recommend the fgets()+sscanf() approach that a lot of other people have suggested. You could also use scanf("%*c"); before the call to getchar(). That will essentially eat a character.
If you are doing this under windows, you can use winapi to flush input buffer before your getch().
#include <windows.h>
hStdin = GetStdHandle(STD_INPUT_HANDLE);
FlushConsoleInputBuffer(hStdin);
-or-
#include <windows.h>
FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
As others already pointed out, you should not write a struct to a file. Instead, try to write the data in a formatted manner. This way your text file can be parsed line-by-line by finding the last and second-to-last delimiters, for example semicolons. Keep in mind that certain characters like '-' or '.' may occur in the stringified float field.
int write_data(FILE *fh, struct emp *e) {
if(fh == NULL || e == NULL)
return -1;
fprintf(fh, "%s;%d;%f", e->name, e->age, e->bs);
return 0;
}
The other thing is how everybody keeps recommending the same scanf family of functions, but nobody ever checks whether the return value is equal to the number of fields to be read. I think that is a bad idea, effectively asking for trouble. Even with the strtol/strtod way you need error checking:
int parse_int(char *buf, long *result) {
if(buf == NULL || result == NULL)
return -1;
errno = 0;
*result = strtoul(buf, NULL, 0);
if(errno != 0) {
perror("strtoul");
return -1;
}
return 0;
}
the two code examples above return silently which is fine if you plan to call them using existing objects all the time; consider printing an error message, though, and illustrate in your documentation that people should check the return values when using your functions.
stdin is not something flushable, you can flush only output streams. I.e. you don't need to call flush on stdin at all.
I'm trying to make a program in C for reading in lines of text from a file, and creating nodes to build a tree. these nodes are structs. To do this, I'm trying to read six lines at a time. whenever my program gets to the fscanf line however, it doesn't seem to read anything, setting my int to EOF and exiting the function. I've tried a great deal of format combinations, removing and adding spaces, \n and the like. I've even tried making a separate fscanf line to attempt to read in a single string, and even that seems to scan nothing. I have no idea why this is happening. here's the relevant code:
member_ptr readAndCreate(FILE * file){
member_node * temp;
temp = calloc(1, sizeof(member_node));
//char temp_char_array[50] = {0,0,0,0,0};
//char *overflow;
int isEnd;
//isEnd = fscanf(file, " %s", temp_char_array);
//isEnd =
isEnd = fscanf(file, " %[^\n] %[^\n] %d %[^\n] %[^\n] %[^\n]",
temp -> family,
temp -> personal,
&temp ->ID,
temp -> email,
temp -> boatClass,
temp -> boatName
);
//temp->ID = (int)strtol(temp_char_array, &overflow, 10);
if (isEnd == EOF){
printf("Something went wrong, please try again \n");
return NULL;
} else {
return temp;
}
}
and this is the main function
int main() {
char pathname[100];
FILE * file;
member_ptr top;
member_ptr temp;
printf("input file path\n");
scanf("%[^\n]", pathname);
file = fopen(pathname, "r");
if (file == NULL){
printf("file cannot be found, closing program...");
exit(1);
}
top = readAndCreate(file);
genTree(top, file);
printOutTree(top);
printf("Hello, World!\n");
return 0;
}
I see a problem with your scan codes. The s designating string input seems to be missing.
Try changing
isEnd = fscanf(file, " %[^\n] %[^\n] %d %[^\n] %[^\n] %[^\n]",
into
isEnd = fscanf(file, " %[^\n]s %[^\n]s %d %[^\n]s %[^\n]s %[^\n]s",
You have the same bug in the main() function.
Sorry for a stupid question, but this is really starting to annoy me.
I need to take a line of input from a console. Here's the relavent fragment of code:
int number_read=0;
char line[80];
printf("Enter register address: ");
number_read = scanf("%s\n", line);
printf("number of characters entered: %d; characters entered: %s.\n", number_read, line);
if (number_read > 0) {
<read some registers and display the results.>
}
It doesn't work. The "Enter register address" line is printed, and the cursor stops at the end of the line, and moves to the next line when I press enter, but then nothing else happens. I've tried replacing scanf() with fscanf(stdin,...), with fgets(stdin), gets, GNU's getline(), a short function that does the same thing, with diagnostics:
char *new_line, ch;
for(;;) {
ch = fgetc(stdin);
if(ch == EOF) break;
if((*line++ = ch) == '\n') break;
printf("Line so far: %s\n", line);
}
*line='\0';
I get the same response from all of them. I'm including all the requisite headers.
I'm on a Windows XP box, compiling with gcc 3.4.5 (mingw).
Can anyone see what I'm doing wrong?
In scanf you should use a %i to represent a int so, try with
scanf("%I", number_line);
The following code will works,
char buff_msg[1024];
while(1)
{
if(fgets(buff_msg,1024, stdin) != NULL){
printf("%s\n", buff_msg);
memset(buff_msg, 0, 1024); // you will need this line
}
}
You can
break the loop on your own condition
try read() it works in MinGW replace
this
number_read = scanf("%s\n", line);
with this also include #include<unistd.h>
number_read = read(STDIN_FILENO, (void *)line,sizeof line);
value scanf returns is not the number of strings in the number of elements to read(this case meybe 1).
Use the %n To get the number, such as desired.
scanf("%s%n", line, &number_read);
printf("number of characters entered: %d; characters entered: %s.\n", number_read, line);
the problem I have is as follows:
I need to create a function in C, using the standard libraries.
This function should read data from standard input as follows: value1 value2 value3
Whose type is uint32_t.
The problem is that I do not like that much data going to enter, I can just finish reading the data when the user enter a line that does not respect the format given, or when entering a line with spaces or when entering an EOF.
I was reading several answers to similar problems in the page and this is the code that I did:
int main(void) {
uint32_t value1, value2, value3;
int ret = 3;
char ch;
while (true) {
printf("Enter the data:\n");
ret = scanf("%u %u %u", &value1, &value2, &value3);
if ((ret != 3) || (getc(stdin) == EOF) ||
(getchar() == ' ')) {
break;
}
printf("\nYou entered: %u, %u, %u\n", value1, value2, value3);
}
printf("Finish..");
return 0;
}
But not working properly.
Any suggestions?
Suggest:
read the line using fgets()
read the line populated by fgets() with sscanf(), similar to how scanf() is currently used
this has the benefit of reading the line always, whereas the posted code needs to discard the line if the scanf() fails, on invalid input for example.
Example:
printf("Enter the data:\n");
char line[1024];
while (fgets(line, 1024, stdin))
{
uint32_t values[3];
if (sscanf(line, "%u %u %u", &values[0], &values[1], &values[2]))
{
printf("\nYou entered: %u, %u, %u\n", values[0], values[1], value[2]);
break;
}
fprintf(stderr, "Invalid input, retry...\n");
}