How input works in C - c

I'm quite confused about the function scanf and how the input works in C.
See this code :
#include<stdio.h>
int main()
{
FILE pt = *stdin;
char b[100];
scanf("%s", b);
scanf("%s", b); //breakpoint here
scanf(" "); //breakpoint here
}
When the code runs, I input 12345 into the console. I found that pt _ptr(which I don't actually know what it is) has the value "12345\n\n" and b[] has the value "12345".
Then I continue the program and input 23456. Now pt _ptr is "23456\n\n" and b[] is "23456".
My question :
How does the input work in C? Why does pt _ptr have the value of "12345\n\n" not "12345\n" since I pressed enter only one time(and it seems like the function scanf skips those two \n after successfully read "12345" ).

You are looking under the carpet... You are not supposed to copy FILE structs so the first line
FILE pt = *stdin;
results are actually undefined. Do not look inside, unless you are willing to read and understand the source of you standard C library!
The rest of the code is pretty easy to understand, as b has always the expected value, isn't it?

It is not apparent what it is you are really trying to do besides learn scanf, but you are also invoking stdin and the FILE struct.
Using fscanf instead, (read link for details on `fscanf) it will be easier to use all three.
Here is a simple example of how you can combine fscanf, FILE, and stdin:
int main(void)
{
FILE *fp={0};
int res =0 //use to check return value of fscanf
char buf[80]; //use 80 for demonstration only
fp = fopen("c:\\dev\\play\\playtext.txt", "w");//create file and stream
res = fscanf(stdin, "%s", buf);//stream input from stdin
if(res == EOF)
{
printf("Exiting... input error");//notify and exit upon error
return -1;
}
while (strstr(buf, "quit") == NULL)//allow exit by typing quit
{
if(fputs(buf, fp) == EOF) return -1;
buf[0]=0;//reset buffer
res = fscanf(stdin, "%s", buf);
if(res == EOF)
{
printf("Exiting... input error");//notify and exit upon error
return -1;
}
}
fclose(fp);
return 0;
}

Related

Using a system call to execute "which" command in C

I'm trying to get the pathname for specific user input. For example, if the user inputs ls | wc I want to create two strings the first one being a which(ls), and the second one being a which(wc) so I have the pathname. I am doing this inside a C program and my code looks like the following.
/*This is a basic example of what i'm trying to do*/
char* temp;
printf("Enter a command\n");
/* assume user enters ls */
scanf("%s", temp);
char* path = system(which temp);
printf("Testing proper output: %s\n", path);
/*I should be seeing "/bin/ls" but the system call doesn't work properly*/
Can anyone point me in the right direction?
You are using an uninitialized pointer. But even if you had initialized it properly, it still wouldn't work because system() doesn't return the output of the command it executes.
You want to use popen() to do that.
Here's an example (untested):
if (fgets(cmd, sizeof cmd, stdin)) {
char cmd[512];
cmd[strcspn(cmd, "\n")] = 0; // in case there's a trailing newline
char which_cmd[1024];
snprintf(which_cmd, sizeof which_cmd, "which %s", cmd);
char out[1024];
FILE *fp = popen(which_cmd);
if (fp && fgets(out, sizeof out, fp)) {
printf("output: %s\n", out);
}
}

Entire file is not read in C (EOF occurs unexpectedly)

I am trying to print contents of a file with approximately 4000 characters.
Somehow the program records only the first 220 characters and terminates.
int main(void)
{
char ch = ' ', file_name[25], payload[3904];
FILE *fp;
printf("Enter the name of file you wish to see\n");
gets(file_name);
fp = fopen(file_name, "r"); // read mode
if (fp == NULL)
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
printf("The contents of %s file are :\n", file_name);
int gin = 0;
while ((ch = fgetc(fp)!=EOF))
{
printf("%d) %x \n",gin, ch);
payload[gin++] = ch;
}
printf("Also, value of gin is %d --->", gin);
getchar();
//...rest of the code
}
Here the value of gin is 220.
Just to check, I modified the while() condition to run for the exact number of characters in the file:
{
//...
while (gin<3904)
{
if ((ch = fgetc(fp)) == EOF) res++;//ADDED THIS TO COUNT NUMBER OF EOF's
printf("%d) %x \n",gin, ch);
payload[gin++] = ch;
//printf(" %x \n", payload[(gin - 1)]);
if (gin % 100 == 0)
{
printf("Also, value of res is %d --->", res); getchar();
getchar();
}
}
//...rest of the code
}
The value of gin reaches 3904, the value of res(no. of EOF's) is 3684, meaning that every character after the first 220 is being read as an EOF. The program starts reading FF after the first 220 character even though it is filled.
I think the code is fine, apart from the fact that you should change the ch to int.
fgetc() returns
If success, "the character read as an unsigned char cast to an int"
In failure, "EOF on end of file or error"
So, first, you have to change the ch to int, as some return values from fgetc() may not fit into a char.
Now, in the second case, you're not checking the return value of fgetc() against EOF to detect any error . You're simply taking the return value and trying to store those values into the array. Actually, when the end of file is reached, there is nothing more to be read, and all the further reads on the same file pointer will return you error.
It is most likely that those values. after 220 in your case are valid , at all.
So, to the statement in your question,
(EOF occurs unexpectedly)
is wrong. It occurs just fine, you're ignoring it and running into, well, trouble.
Note:
In your first snippet, you're doing two successive fgetc() calls, essentially discarding the result of the first one, and using the second one without any check.
Never use gets(). It suffers from buffer overflow issues. Always use fgets() instead.
the following code:
uses fgets() rather than the obsolete gets()
removed the newline from the user input
uses the proper size_t rather than int for indexing
is consistently indented
has modification to the printf statements to display size_t rather than int
compiles cleanly (which surprises me as payload is set but never used)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int ch = ' ';
char file_name[25];
char payload[3904];
FILE *fp;
printf("Enter the name of file you wish to see\n");
fgets(file_name, sizeof(file_name), stdin);
// remove trailing newline
char *newline = strstr(file_name, "\n" );
if (newline ) *newline = '\0';
fp = fopen(file_name, "r"); // read mode
if (fp == NULL)
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
// implied else, fopen successful
printf("The contents of %s file are :\n", file_name);
size_t gin = 0;
while ( ((ch = fgetc(fp)!=EOF)) && (sizeof(payload) > gin) )
{
printf("%ld) %x \n",gin, ch);
payload[gin++] = ch;
}
printf("Also, value of gin is %ld --->", gin);
getchar();
//...rest of the code
return(0);
}

Why does this code compile but not actuall work?

Line 12 to 23 runs. But doesn't actually run when the if statement is added. it does compile and runs. It asks the first printf statement then terminates when I choose a character. Why is this happening and how do I fix it.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char ch, file_name[25];
FILE *fp;
printf("Enter [A] and select file or [X] to exit:"); // Prompt user to select file or exit
scanf("%c",&ch);
scanf("%c",&ch);
if (ch=='A')
{
printf("Enter the file name\n"); // if user chooses 'A' this code should run
gets(file_name);
fp = fopen(file_name,"r"); // reading file
if( fp == NULL )
{
perror("File not found.\n");
exit(EXIT_FAILURE);
}
printf("Contents of %s are:\n", file_name);
while( ( ch = fgetc(fp) ) != EOF )
printf("%c",ch);
}
else if (ch=='X')
{
printf("Exiting program...");
exit(0);
}
}
Because you have two calls to scanf..
In the first one, you are reading your input 'A' or 'X' successfully.
In the next call, you are reading the newline character(\n) which was pressed earlier into the same variable ch. So it doesn't satisfy any if clause and simply comes out of program..
Instead make second call to temporary variable..
char temp;
scanf("%c", &temp);
Also fgets is preferred over gets
I guess you are not reading properly from the file , Try:
char buff[255]; //define buffer to read lines
while ( !feof(fp ) ){
memset(buff, '\0', sizeof( buff) );
fgets(buff, 255, (FILE*)fp);
printf("%s", buff );
}
fclose(fp); //don't forget to close
There are a large class of programs that compile yet don't run properly. That's why a distinction is made between syntax errors and runtime/logic errors.
scanf("%c",&ch);
scanf("%c",&ch);
I'm assuming that's to get rid of the newline character but it's a bad idea to read it into ch, since that should keep the first character.
If that is the case, simply read it into some junk variable so that ch is preserved.
char ch, junk, file_name[25];
:
scanf("%c",&ch);
scanf("%c",&junk);
Sadly though, there may be numerous other problems with this approach. If you want a decent line input function, you can find one here. That's much better than using gets(), which is inherently unsafe.
It has buffer overflow detection and prevention, automatic flushing of input lines where too long, prompt output and so on. Once you've used it to get an input line, all you need to do is compare that with what you want, something like:
if (strcmp (buff, "A") == 0)
doSectionA();
else
if (strcmp (buff, "X") == 0)
doSectionX();

function using fopen() keeps opening the same file, even if given different filenames as parameters

I'm trying to open multiple files sequentially, using fopen(), just printing the contents and counting the chars.
In main() I call the function twice using different filenames but the function just prints the contents of the first file twice. Both files do exist, of course, and just calling this function once does print the correct contents; tested with both files. There just seems to be a problem when calling the function multiple times.
Can somebody please give me a hint? What could be wrong?
My function:
void open_and_read(char file_name[80]){
char c;
int buf_length = 16384;
char buf[buf_length];
char* buf_pointer;
int i = 0;
FILE *file_pointer;
file_pointer = fopen(file_name,"r");
buf_pointer = buf;
if(file_pointer==NULL){
printf("Error: File %s not opened!", file_name);
}
else {
while(c!=EOF && i<(buf_length-1)){
c = fgetc(file_pointer);
*buf_pointer = c;
buf_pointer++;
i++;
}
buf_pointer--;
*buf_pointer = 0;
printf("The file %s contains the follwing: \n%s", file_name, buf);
printf("char-count: %i\n", i);
}
if(fclose(file_pointer)!=0){
printf("File was not closed!");
}
else {
printf("File was successfully closed!");
}
}
main():
int main(){
open_and_read("/home/x201/dev/IB/data/line1.dat");
open_and_read("/home/x201/dev/IB/data/line2.dat");
char c;
This is not initialised anywhere. Try char c = '\0' .
Edit:
It would be much appropriate if you would use
while(((c = fgetc(file_pointer))!= EOF) && i<(buf_length-1))
There won't be any need to initialise c. You will receive its value from fgetc itself
before you enter the loop for the 1st time.
if your file is empty, your "buf_pointer--;" will point to SOMETHING;
Use char c ='\0';
as char c is not initialized so as auto variable it will contain garbage.
Here the problem is of char variable "c".
Which will be EOF while calling the function open_and_read second time and it will not go inside the while loop and the contains of the sencond file will not be read and displayed the previous file contains.
solution to this is :-
char c='\0'

reading primitives from file in C

I am new to C, and want to read some data from a file.
Actually, I find many reading functions, fgetc, fgets, etc..
But I don't know which one/combination is the best to read a file with the following format:
0 1500 100.50
1 200 9
2 150 10
I just need to save each row above into a struct with three data members.
I just need to know the best practice to do that, hence I am new to C programming.
Thanks.
Try reading each line using fgets. With each line, you can then use sscanf.
FILE* f = fopen("filename.txt", "r");
if (f) {
char linebuff[1024];
char* line = fgets(linebuff, 1024, f);
while (line != NULL) {
int first, second;
float third;
if (sscanf(line, "%d %d %g", &first, &second, &third) == 3) {
// do something with them..
} else {
// handle the case where it was not matched.
}
line = fgets(linebuff, 1024, f);
}
fclose(f);
}
This may have errors, but it's just meant to give you an example of how you might use the functions. Be sure to validate what sscanf returns you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void
read_file(const char *fname)
{
FILE *f;
char line[1024];
int lineno, int1, int2, nbytes;
double dbl;
if ((f = fopen(fname, "r")) == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
for (lineno = 1; fgets(line, sizeof line, f) != NULL; lineno++) {
int fields = sscanf(line, " %d %d %lg %n", &int1, &int2, &dbl, &nbytes);
if (fields != 3 || (size_t) nbytes != strlen(line)) {
fprintf(stderr, "E: %s:%d: badly formatted data\n", fname, lineno);
exit(EXIT_FAILURE);
}
/* do something with the numbers */
fprintf(stdout, "number one is %d, number two is %d, number three is %f\n", int1, int2, dbl);
}
if (fclose(f) == EOF) {
perror("fclose");
exit(EXIT_FAILURE);
}
}
int main(void)
{
read_file("filename.txt");
return 0;
}
Some notes on the code:
The fscanf function is quite difficult to use. I had to experiment a while until I got it right. The space characters between the %d and %lg are necessary so that any white-space between the numbers is skipped. This is especially important at the end of the line, where the newline character must be read.
Most of the code is concerned with checking errors thoroughly. Almost every return value of a function call is checked whether it succeeded or not. In addition, the number of fields and the number of characters that have been read are compared to the expected values.
The format strings for fscanf and fprintf differ in subtle details. Be sure to read the documentation for them.
I used the combination of fgets to read one line at a time and sscanf to parse the fields. I did this because it seemed impossible to me to match a single \n using fscanf.
I used the GNU C Compiler with the standard warning flags -Wall -Wextra. This helped to avoid some easy mistakes.
Update: I forgot to check that each invocation of fgets reads exactly one line. There might be lines that are too long to fit into the buffer. One should check that the line always ends with \n.

Resources