Why does this code compile but not actuall work? - c

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();

Related

C code to write content to a file not working

This is the c code that I wrote to write something to a file. But when I compile it, the process terminates without getting input for the contents. What is the error?
#include <stdio.h>
#include <string.h>
void main()
{
FILE *fp;
char name[20];
char content[100];
printf("Enter file name:\n");
scanf("%s", name);
printf("Enter the content:\n");
gets(content);
fp = fopen(name, "w");
fprintf(fp, "%s", content);
fclose(fp);
}
It blew right past the gets line. Why? Because the scanf family has lots and lots of problems. Avoid them.
Specifically it tends to leave input on the buffer. In this case scanf("%s", name); read in all the text and left a newline on stdin. Then gets dutifully read that newline... and throws it out because that's how gets behaves. We can see this if we print name and content just before gets.
printf("name: '%s'\n", name);
printf("content: '%s'\n", content);
name: 'foo'
content: ''
Then your program dutifully writes nothing to the file.
Instead, use fgets to read entire lines, and sscanf to parse them. This avoids the danger of leaving input on the buffer.
printf("Enter file name:\n");
fgets(name, sizeof(name), stdin);
printf("Enter the content:\n");
fgets(content, sizeof(content), stdin);
fgets does not strip newlines, so you'll have to do that yourself. There's a variety of ways to do it.
void trim( char *string, char to_trim ) {
size_t len = strlen(string);
if( len == 0 ) {
return;
}
size_t last_idx = len -1;
if( string[last_idx] == to_trim ) {
string[last_idx] = '\0';
}
}
I prefer this approach because it only removes the newline if it's the final character.
Finally, always check your file operations. You're not checking if the fopen succeeded. If it fails for whatever reason you'll get another mysterious error. In my case the name I was using for testing already existed as a directory.
#include <string.h> // for strerror
#include <errno.h> // for errno
fp = fopen(name, "w");
if( fp == NULL ) {
fprintf(stderr, "Could not open '%s' for writing: %s.\n", name, strerror(errno));
return 1;
}

Why "scanf" works but fgets doesn't works in C?

Look here, those two programms should be equivalent in my opinion. But obviously they aren't, as the first programm works and the second doesn't. Can someone explain to me, why fgets() doesn't do the job?
// FIRST PROGRAM : WORKS FINE
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *stream;
char fileName[67];
scanf("%s", fileName);
printf("%s", fileName);
stream = fopen(fileName, "r");
char ch;
if(stream){
ch = fgetc(stream);
while(!feof(stream)){
putchar(ch);
ch = fgetc(stream);
}
fclose(stream);
}
}
// SECOND PROGRAM: DOES NOT WORK
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *stream;
char fileName[67];
fgets(fileName, 67, stdin);
printf("%s", fileName);
stream = fopen(fileName, "r");
char ch;
if(stream){
ch = fgetc(stream);
while(!feof(stream)){
putchar(ch);
ch = fgetc(stream);
}
fclose(stream);
}
}
I enter "test.txt" into the console both times and press enter then. Of course test.txt exists in the right directory
The reason is that fgets() retains the newline entered. You can verify it is there by altering your print statement to
printf("[%s]", filename);
when the ] will appear on the next line. You can remove the trailing newline like this
#include <string.h>
...
filename [ strcspn(filename, "\r\n") ] = 0;
The main problem you experienced is correctly solved by Weather Vane, but I want to point another problem with your code: the loops for reading and writing the contents of the file are incorrect. Testing the end of file with feof(stream) leads to incorrect behaviour most of the time. In your case, a read error from stream will cause your program to loop endlessly, writing 0xFF bytes to stdout.
There is a much simpler and idiomatic way to implement this loop:
if (stream) {
int ch;
while ((ch = fgetc(stream)) != EOF) {
putchar(ch);
}
fclose(stream);
}
As you can see, it is simpler and correctly tests for EOF at the right time, when input fails. It stores the return value of fgetc() into an int variable capable of holding all possible return values from fgetc(). Using an int is necessary because comparing a char value to EOF either always fails if the char type is unsigned or potentially gives false positives if char is signed and has value '\377'.

How do I store a text file into an array in C

I am trying to open a text file inputted by the user and read this text file but print the text file 60 characters at a time so I think in order for me to do this I need to store the text into an array and if it is over 60 characters on a line it should start on a new line. However, when I run the code below an error message shows up saying : C^#
#include <stdio.h>
#include <stdlib.h>
int main()
{
char arr[];
arr[count] = '\0';
char ch, file_name[25];
FILE *fp;
printf("Enter file name: \n");
gets(file_name);
fp = fopen(file_name,"r"); // reading the file
if( fp == NULL )
{
perror("This file does not exist\n"); //if file cannot be found print error message
exit(EXIT_FAILURE);
}
printf("The contents of %s file are :\n", file_name);
while( ( ch = fgetc(fp) ) != EOF ){
arr[count] = ch;
count++;
printf("%s", arr);}
fclose(fp);
return 0;
}
char arr[]; is invalid.you need to specify a size.
array[count] = '\0'; : count is uninitialized.
gets(file_name); : gets is deprecated and dangerous.use another function like scanf.
Try the following code :
#include <stdio.h>
#include <stdlib.h>
int main()
{
int ch , count = 0;
char file_name[25];
FILE *fp;
printf("Enter file name: \n");
scanf(" %24s",file_name);
fp = fopen(file_name,"r"); // reading the file
if( fp == NULL )
{
perror("This file does not exist\n"); //if file cannot be found print error message
exit(EXIT_FAILURE);
}
fseek(fp, 0L, SEEK_END);
long sz = ftell(fp);
fseek(fp, 0L, SEEK_SET);
char arr[sz];
while( ( ch = fgetc(fp) ) != EOF )
{
if( count < sz )
{
arr[count] = ch;
count++;
}
}
arr[sz] = '\0';
printf("The contents of %s file are :\n", file_name);
printf("arr : %s\n",arr);
fclose(fp);
return 0;
}
fgetc always reads the next character until EOF. use fgets() instead:
char *fgets(char *s, int size, FILE *stream)
fgets() reads in at most one less than size characters from stream and
stores them into the buffer pointed to by s. Reading stops after an EOF
or a newline. If a newline is read, it is stored into the buffer. A
terminating null byte (aq\0aq) is stored after the last character in the
buffer.
1) your while loop is not properly delimited. In the absence of a { } block, the instruction arr[count] = ch; is the only repeted one.
I suppose it should include the incrementation of count too
while( ( ch = fgetc(fp) ) != EOF )
{
arr[count] = ch;
count++;
....
}
among other things (testing the counter etc).
2) there's no imperative need to read and store in an array. It is perfectly possible to transfer each character as soon as it is read, and add a line break when needed (new line, limit of 60 exceeded).
Three problems:
The variable count is not initialized, so it's value is indeterminate and using it will lead to undefined behavior.
The call printf(arr) treats arr as a string but arr is not terminated which again leads to undefined behavior.
The increment of count is outside the loop.
To solve the two first problems you must first initialize count to zero, then you must terminate the string after the loop:
arr[count] = '\0';
However, your printf(arr) call is still very problematic, what if the user enters some printf formatting codes, what will happen then? That's why you should never call printf with a user-provided input string, instead simply do
printf("%s", arr);
You also have a very big problem if the contents of the file you read is longer than 59 characters, and then you will overflow the array.

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);
}

How input works in 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;
}

Resources