These are the contents of my file, 'unsorted.txt' :
3 robert justin trump
This is my code:
#include <stdio.h>
int main(void) {
FILE *f = fopen("unsorted.txt", "r");
char n;
printf("%d\n", ftell(f));
fscanf(f, "%s", &n);
int l = n - '0';
printf("%d %d\n", l, ftell(f));
return 0;
}
on execution it gives the following output:
0
3 -1
why did it return -1 in second case? It should move from 0 to 1 right?
NOTE: the file can be opened, because then how would it print 0 in the first call and the first character from the file without being able to be opened?
fscanf(f,"%s",&n);
is very wrong, since you declared char n; (of only one byte). You got undefined behavior. Be very scared (and next time, be ashamed).
I recommend:
Test that fopen don't fail:
FILE *f = fopen("unsorted.txt","r");
if (!f) { perror("fopen unsorted.txt"); exit(EXIT_FAILURE); };
Declare a buffer of reasonable size (80 was the size of punched cards in the 1970s).
char buf[80];
clear it (you want defensive programming):
memset(buf, 0, sizeof(buf));
Then read carefully about fscanf. Read that documentation several times. Use it with a fixed size and test its result:
if (fscanf(f, "%72s", buf) > 0) {
(72 was the usable size in PL/1 programs of punched cards; it is less than 80)
Don't forget to read documentation of other functions, including ftell.
Important hint:
compile with all warnings and debug info (gcc -Wall -Wextra -g with GCC), improve the code to get no warnings, use the debugger gdb to run it step by step.
PS. As an exercise, find the possible content of unsorted.txt which made your initial program run correctly. Could you in that case predict its output? If not, why??
There are multiple problems in your code:
You do not test the return value of fopen(). Calling ftell() with a NULL pointer has undefined behavior. You cannot draw conclusions from observed behavior.
printf("%d\n", ftell(f)); is incorrect because the return value of ftell() is a long. You should use the format %ld.
fscanf(f, "%s", &n); is incorrect because you pass the address of a single char for fscanf() to store a null-terminated string. fscanf() will access memory beyond the size of the char, which has undefined behavior. Define an array of char such as char buf[80]; and pass the maximum number of characters to store as: fscanf(f, "%79s", buf); and check the return value, or use %c to read a single byte.
int l = n - '0'; is not strictly incorrect, but it is error prone: avoid naming a variable l as it looks confusingly similar to 1.
printf("%d %d\n", l, ftell(f)); is incorrect as the previous call to printf: use the conversion specifier %ld for the return value of ftell().
Note also that the return value of ftell() on a text stream is not necessarily the byte offset in the file.
Here is a corrected version:
#include <stdio.h>
int main(void) {
FILE *f = fopen("unsorted.txt", "r");
char c;
if (f != NULL) {
printf("%ld\n", ftell(f));
if (fscanf(f, "%c", &c) == 1) {
int diff = c - '0';
printf("%d %ld\n", diff, ftell(f));
}
}
return 0;
}
Output:
0
3 1
Related
I can't understand why function fread() behaves differently in these 2 examples:
1)
I have a structure with a short and a char (size is 4 bytes including padding) and an array of three such structures.If I write each short and char of each structure separately with fwrite() and then read that file with fread() to a variable whose type is that structure, I will read 4 bytes at a time (there will be 9 bytes in the file) so you can see that one byte will be left in 3rd iteration (and one byte will be lost in each iteration).What happens is that there is no 3rd read because I'm left with one byte and fread has to read 4 bytes.
2)
A simpler example, if I write a 1 byte char to a file with fwrite() and then put the content of that file into a 4 byte int with fread(), the integer will get that data.
Why does this happen?Why does the data get read in one case but not in the other if EOF is reached?
Here is the first example:
int main()
{
struct X { short int s; char c; } y, x[]=
{{0x3132,'3'},{0x3435,'6'},{0x3738,'9'}};
FILE *fp=fopen("FILE.DAT","wb+");
if (fp)
{
for(int i=0;i<sizeof(x)/sizeof(x[i]);)
{
fwrite(&x[i].s,sizeof(x[i].s),1,fp);
fwrite(&x[i].c,sizeof(x[i].c),1,fp);
i++;
}
rewind(fp);
for(int i=0;fread(&y,sizeof(y),1,fp);)
printf("%d:%x %c\n",++i, y.s, y.c);
fclose(fp);
}
return 0;
}
Second example:
int main()
{
FILE *fp=fopen("FILE.DAT","wb+");
char c = 'a';
fwrite(&c, sizeof(c), 1, fp);
rewind(fp);
int num;
fread(&num, sizeof(num), 1, fp);
fclose(fp);
return 0;
}
Why does the data get read in one case but not in the other if EOF is reached?
"What happens is that there is no 3rd read because I'm left with one byte and fread has to read 4 bytes." is a questionable premise.
1st Code did read 3 times. There are with no bytes left to read.
In both codes, the last read was a partial read with a fread() return value of 0.#Useless
(The first code did not print the result of the 3rd read.)
With fread(), a return value of 0 does not mean "end-of-file" was immediately encountered - nothing read. Instead, 0 means an complete read did not occur due to :
* "end-of-file" or partial read.
* rare I/O error.
Why does this happen?
In the 2nd code, results may differ due to Indeterminate behavior
fread() ... If a partial element is read, its value is indeterminate1 C11dr ยง7.21.8.1 2
fread(&num, sizeof(num), 1, fp) result may or may not be as expected.
A more informative example
int main(void) {
FILE *fp = fopen("FILE.DAT", "wb+");
char c = 'a';
printf(" %8X\n", c);
fwrite(&c, sizeof(c), 1, fp);
rewind(fp);
unsigned num = rand();
printf(" %8X\n", num);
size_t len = fread(&num, sizeof(num), 1, fp);
printf("%zu %8X\n", len, num);
len = fread(&num, sizeof(num), 1, fp);
printf("%zu\n", len);
fclose(fp);
return 0;
}
Output
61 as expected
5851F42D as expected - some random value
0 5851F461 Indeterminate! (in this case, looks like the LSByte was replaced.)
0 as expected
Moral of the story: assess the return value of fread() before relying on what was read into the buffer.
1 indeterminate value
either an unspecified value or a trap representation
... when EOF is reached ...
EOF isn't "reached". Many <stdio.h> functions return EOF as a signal that something went wrong, giving no indication what that something is. If you want to know what went wrong after receiving the signal, test with feof() and/or ferror().
My problem is when I try to save the string (series[0]) Inside (c[0])
and I display it, it always ignore the last digit.
For Example the value of (series[0]) = "1-620"
So I save this value inside (c[0])
and ask the program to display (c[0]), it displays "1-62" and ignores the last digit which is "0". How can I solve this?
This is my code:
#include <stdio.h>
int main(void)
{
int price[20],i=0,comic,j=0;
char name,id,book[20],els[20],*series[20],*c[20];
FILE *rent= fopen("read.txt","r");
while(!feof(rent))
{
fscanf(rent,"%s%s%s%d",&book[i],&els[i],&series[i],&price[i]);
printf("1.%s %s %s %d",&book[i],&els[i],&series[i],price[i]);
i++;
}
c[0]=series[0];
printf("\n%s",&c[0]);
return 0;
}
The use of fscanf and printf is wrong :
fscanf(rent,"%s%s%s%d",&book[i],&els[i],&series[i],&price[i]);
Should be:
fscanf(rent,"%c%c%s%d",&book[i],&els[i],series[i],&price[i]);
You have used the reference operator on a char pointer when scanf expecting a char pointer, also you read a string to book and else instead of one character.
printf("1.%s %s %s %d",&book[i],&els[i],&series[i],price[i]);
Should be:
printf("1.%c %c %s %d",book[i],els[i],series[i],price[i]);
And:
printf("\n%s",&c[0]);
Should be:
printf("\n%s",c[0]);
c is an array of char * so c[i] can point to a string and that is what you want to send to printf function.
*Keep in mind that you have to allocate (using malloc) a place in memory for all the strings you read before sending them to scanf:
e.g:
c[0] = (char*)malloc(sizeof(char)*lengthOfString+1);
and only after this you can read characters in to it.
or you can use a fixed size double character array:
c[10][20];
Now c is an array of 20 strings that can be up to 9 characters long.
Amongst other problems, at the end you have:
printf("\n%s",&c[0]);
There are multiple problems there. The serious one is that c[0] is a char *, so you're passing the address of a char * โ a char ** โ to printf() but the %s format expects a char *. The minor problem is that you should terminate lines of output with newline.
In general, you have a mess with your memory allocation. You haven't allocated space for char *series[20] pointers to point at, so you get undefined behaviour when you use it.
You need to make sure you've allocated enough space to store the data, and it is fairly clear that you have not done that. One minor difficulty is working out what the data looks like, but it seems to be a series of lines each with 3 words and 1 number. This code does that job a bit more reliably:
#include <stdio.h>
int main(void)
{
int price[20];
int i;
char book[20][32];
char els[20][32];
char series[20][20];
const char filename[] = "read.txt";
FILE *rent = fopen(filename, "r");
if (rent == 0)
{
fprintf(stderr, "Failed to open file '%s' for reading\n", filename);
return 1;
}
for (i = 0; i < 20; i++)
{
if (fscanf(rent, "%31s%31s%19s%d", book[i], els[i], series[i], &price[i]) != 4)
break;
printf("%d. %s %s %s %d\n", i, book[i], els[i], series[i], price[i]);
}
printf("%d titles read\n", i);
fclose(rent);
return 0;
}
There are endless ways this could be tweaked, but as written, it ensures no overflow of the buffers (by the counting loop and input conversion specifications including the length), detects when there is an I/O problem or EOF, and prints data with newlines at the end of the line. It checks and reports if it fails to open the file (including the name of the file โ very important when the name isn't hard-coded and a good idea even when it is), and closes the file before exiting.
Since you didn't provide any data, I created some random data:
Tixrpsywuqpgdyc Yeiasuldknhxkghfpgvl 1-967 8944
Guxmuvtadlggwjvpwqpu Sosnaqwvrbvud 1-595 3536
Supdaltswctxrbaodmerben Oedxjwnwxlcvpwgwfiopmpavseirb 1-220 9698
Hujpaffaocnr Teagmuethvinxxvs 1-917 9742
Daojgyzfjwzvqjrpgp Vigudvipdlbjkqjm 1-424 4206
Sebuhzgsqpyidpquzjxswbccqbruqf Vuhssjvcjjylcevcisdzedkzlp 1-581 3451
Doeraxdmyqcbbzyp Litbetmttcgfldbhqqfdxqi 1-221 2485
Raqqctfdlhrmhtzusntvgbvotpk Iowdcqlwgljwlfvwhfmw 1-367 3505
Kooqkvabwemxoocjfaa Hicgkztiqvqdjjx 1-466 435
Lowywyzzkkrazfyjuggidsqfvzzqb Qiginniroivqymgseushahzlrywe 1-704 5514
The output from the code above on that data is:
0. Tixrpsywuqpgdyc Yeiasuldknhxkghfpgvl 1-967 8944
1. Guxmuvtadlggwjvpwqpu Sosnaqwvrbvud 1-595 3536
2. Supdaltswctxrbaodmerben Oedxjwnwxlcvpwgwfiopmpavseirb 1-220 9698
3. Hujpaffaocnr Teagmuethvinxxvs 1-917 9742
4. Daojgyzfjwzvqjrpgp Vigudvipdlbjkqjm 1-424 4206
5. Sebuhzgsqpyidpquzjxswbccqbruqf Vuhssjvcjjylcevcisdzedkzlp 1-581 3451
6. Doeraxdmyqcbbzyp Litbetmttcgfldbhqqfdxqi 1-221 2485
7. Raqqctfdlhrmhtzusntvgbvotpk Iowdcqlwgljwlfvwhfmw 1-367 3505
8. Kooqkvabwemxoocjfaa Hicgkztiqvqdjjx 1-466 435
9. Lowywyzzkkrazfyjuggidsqfvzzqb Qiginniroivqymgseushahzlrywe 1-704 5514
10 titles read
I wrote a small program to get the magic number from an .au file and print it to console, but every time I try, instead of getting the intended .snd, I get .snd$ instead.
I'm not sure why this is happening, considering that I'm only reading in 4 bytes, which is what the magic number is comprised of. So, where is the extra character coming from?
#include <stdio.H>
int main()
{
FILE *fin;
int r;
char m[4], path[20];
scanf("%s", path);
fin = fopen(path, "r");
r = fread(&m, sizeof(char), 4, fin);
printf("magic number is %s\n", m);
return 0;
}
You're printing it as though it were a string, which in C, means that it's NUL-terminated. Change your code like this and it will work as you expect:
char m[5];
m[4] = '\0'; /* add terminating NUL */
Also, you should be aware that scanf is a dangerous function. Use a command line argument instead.
The problem is not how you are reading.
The problem is that your variable is only 4 chars length, and it needs a null character to indicate the end.
printf with %s will print the content of the variable until reach a null character, until that it can print garbage if your variable is not correctly ended.
To fix you can have a bigger variable and set the [4] char with null.
How the new code should look like:
#include <stdio.H>
int main()
{
FILE *fin;
int r;
char m[5], path[20];
scanf("%s", path);
/*Scanf can be dangerous because it can cause buffer overflow,
it means that you can fill your variable with more bytes than it supports, which can end up being used for buffer overflow attacks:
See more: http://en.wikipedia.org/wiki/Buffer_overflow */
fin = fopen(path, "r");
r = fread(&m, sizeof(char), 4, fin);
m[4] = '\0';
printf("magic number is %s\n", m);
return 0;
}
I want read from a .txt file which contains english sentences and store them into a character array. Each character by character. I tried but got segmentation fault:11 . I have trouble with fscanf and reading from a file in C.
#include<stdio.h>
#include<math.h>
#include<limits.h>
int main()
{
FILE* fp = fopen("file1.txt","r");
char c , A[INT_MAX];
int x;
while(1)
{
fscanf("fp,%c",&c);
if(c == EOF)
{break;}
A[x] = c;
x++;
}
int i;
for (i=0;i<x;i++)
printf("%c",A[i]);
return 0;
}
Problem 1: Putting the array onto the stack as A[INT_MAX] is bad practice; it allocates an unreasonable amount of space on the stack (and will crash on machines where INT_MAX is large relative to the size of memory). Get the file size, then malloc space for it.
fseek(fp, SEEK_END);
long size = ftell(fp);
rewind(fp);
char *A = malloc((size_t) size); // assumes size_t and long are the same size
if (A == NULL) {
// handle error
}
Problem 2: The fscanf is wrong. If you insist on using fscanf (which is not a good way to read an entire file; see problem 4), you should change:
fscanf("fp,%c",&c);`
should be
int count = fscanf(fp, "%c",&c);
if (count <= 0)
break;
Problem 3: Your x counter is not initialized. If you insist on using fscanf, you'd need to initialize it:
int x = 0;
Problem 4: The fscanf is the wrong way to read the entire file. Assuming you've figured out how large the file is (see problem 1), you should read the file with an fread, like this:
int bytes_read = fread(A, 1, size, fp);
if (bytes_read < size) {
// something went wrong
}
My initial answer, and a good general rule:
You need to check the return value, because your c value can never be EOF, because EOF is an int value that doesn't fit into a char. (You should always check return values, even when it seems like errors shouldn't happen, but I haven't consistently done that in the code above.)
From http://www.cplusplus.com/reference/cstdio/fscanf/ :
Return Value
On success, the function returns the number of items of the argument list successfully filled. This count can match the expected number of items or be less (even zero) due to a matching failure, a reading error, or the reach of the end-of-file.
If a reading error happens or the end-of-file is reached while reading, the proper indicator is set (feof or ferror). And, if either happens before any data could be successfully read, EOF is returned.
If an encoding error happens interpreting wide characters, the function sets errno to EILSEQ.
Hi you should declear till where the program should read data. You can access all characters even if you read line like a string.
try it out
#include<stdio.h>
#include<string.h>
#define INT_MAX 100
int main()
{
FILE* fp = fopen("file1.txt","r");
char c , A[INT_MAX];
int i;
int x;
j=0
while(fscanf(fp,"%s",A[j])!=EOF)
{
j++;
}
int i;
int q;
for(q=0;q<j;q++)
{
for (i=0;i<strlen(A[q]);i++)
printf("%c ",A[q][i]);
printf("\n");
}
return 0;
}
I'm reading in an NES ROM file, where the first four bytes are "\x4e\x45\x53\x1a", or NES\x1a. In my actual code, the given file can be arbitrary, so I want to check to make sure this header is here. However, I'm running into some trouble, which the following code demonstrates:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;
fp = fopen("mario.nes", "rb");
char nes[4];
char real_nes[4] = "NES\x1a";
fread(nes, 4, 1, fp);
printf("A: %x\n", nes[3]);
printf("B: %x\n", real_nes[3]);
printf("C: %s\n", nes);
printf("D: %s\n", real_nes);
if (strcmp(nes, real_nes) != 0) {
printf("not a match\n");
}
fclose(fp);
return 0;
}
which returns:
A: 1a
B: 1a
C: NES?
D: NES
not a match
where the question mark is \x1a.
I'm new to C, so it's possible I'm missing something subtle (or obvious) about why the two strings don't match, and why the question mark doesn't show when printing line D, to signify that \x1a is there at the end of the string, which line B seems to indicate it should be.
Some remarks and suggestions:
open the files in binary mode - otherwise, funny things may happen on non-POSIX systems (fixed)
fp = fopen("mario.nes", "rb");
null-terminate your buffers if you want to print or compare them or use functions like strncmp() which accept the string's length as extra argument
printf("C: %.4s\n", nes);
printf("D: %.4s\n", real_nes);
if (strncmp(nes, real_nes, 4) != 0) {
'\x1a' is the non-graphic substitute character ^Z
check the return values of io functions for errors
Well, one problem is your use of strcmp. This function expects a ZERO-TERMINATED string (neither nes nor real_nes are zero-terminated string in your code).
Another problem is fread. Use it like this:
fread(nes, 1, 4, fp); // first size_t param is size and second is member count
Change your code like this:
int main()
{
FILE *fp;
fp = fopen("mario.nes", "rb");
char nes[5];
char real_nes[5] = "NES\x1a";
fread(nes, 1, 4, fp);
nes[4] = '\0';
printf("A: %x\n", nes[3]);
printf("B: %x\n", real_nes[3]);
printf("C: %s\n", nes);
printf("D: %s\n", real_nes);
if (strcmp(nes, real_nes) != 0) {
printf("not a match\n");
}
fclose(fp);
return 0;
}
And see if it works.
The major problem in your code is:
char real_nes[4] = "NES\x1a";
This not a string, since it does not end with the nul-terminator char ('\0').
This is the same problem for 'nes'.
Just declare them like:
char real_nes[] = "NES\x1a"; /* this is a string, ended by '\0' */
char nes[sizeof real_nes];
To be sure that there is enouth place for the '\0'.
Now you can use the %s specifier, or strcmp(). Anyway, I recommand the use of strncmp() instead, like in:
if(0 != strncmp(real_nes, nes, sizeof real_nes)) { /* some stuff */ }
HTH.
Do not use string functions on not-zero-terminated byte arrays.
The problem is you have two 4 byte arrays which should contain the string "NES\x1a" (no space left for '\0' since it is already 4 bytes long), but the %s format and the strcmp need a '\0' termination at the end to know the strings end. That's why it doesn't work correctly.
1.: Do not use printf with %s format on this byte array.
2.: Use memcmp to compare the bytes.
Try this instead:
int i;
printf("Read bytes: 0x");
for(i = 0; i < sizeof(nes); i ++)
printf("%02X", nes[i]);
printf("\n");
if (memcmp(nes, real_nes, sizeof(nes)) != 0) {
printf("not a match\n");
}
A little too late maybe, but here's how I do it:
// Read the 16 byte iNES header
char header[16];
fread( header, 16, 1, file );
// Search for the "NES^Z" signature
if( memcmp( header, "NES\x1A", 4 ) )
{
As Xeno proposed, with memcmp you don't care about null terminators. After all, you are not really using strings, but more like char arrays, which is not the same due to the null terminators. As you don't really need to print the signature other than for debugging, you shouldn't care using string functions at all.