I tried to read 7 bytes from the file self_tutor.txt into the buff. But somehow the read was not successful. I have checked the syntax for read and the corresponding parameters to be used, but I am not sure where the error comes from. Also what would be the proper way of outputting value from buff if buff was successfully write with the 7 bytes of values from self_tutor.txt?
will a while loop work?
// will this work if the total number of bytes is less than I request? like there
// is only 5 bytes in the self_tutor.txt file but I request to read 7? (i.e. short-read)
while(buff!= EOF) { // will EOF work if I have short-read
printf("value of character inside the buff:%c\n ", *buff);
buff++;
}
or should it be:
while(buff!= "\n") { // so "\n" will be able to handle short-read, is it correct?
printf("value of character inside the buff:%c\n ", *buff);
buff++;
}
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
printf("Hello World\n");
int f1 = open("self_tutor.txt", O_RDONLY);
char *buff;
int f2 = read(f1, buff, 7);
printf("value of f2 :%d\n ", f2); // f2 = -1, so read was not successful
// how to print all the bytes in buff from beginning of buff to end of buff
printf("value of buff:%c\n ", *buff);
return 0;
}
this is the contents of my self_tutor.txt file:
In our Y86-64 simulator. This course is pretty interesting but hard.
A related question is:
A short read may indicate end of file but does not necessarily do so.
what does it mean, does it mean if I have a short-read the following
read(f1, buff, 7);
will not necessarily produce the value 0?
i.e. read(f1, buff, 7) might equal a non-zero value?
thanks
You code never assigns any value to buff. So you are passing garbage to read. You need to make buff point to the place you want the character you read to be stored before you pass its value to read.
Related
I have a simple code that suppose to read length sized and fetch data from character device in Linux C.
This is my code and errno is set to 9. I made sure the file exists and it does. And able to read it with cat /dev/mychardev-0 but why bad file descriptor error at time of read. I am getting this line passed int fd=open("/dev/mychardev-0",O_RDONLY); if(fd<0)
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
int main()
{
int fd=open("/dev/mychardev-0",O_RDONLY);
if(fd<0)
{
printf("fd %d\n",fd);
exit(0);
}
int length=1024000;
int x=0;
char buffer[length-1];
while(x<length)
{
int valread=read(fd,&buffer[x],length);
if(valread==0)
{
printf("zero bytes read\n");
break;
}
if(valread<0)
{
printf("read return negative %d %d\n",valread,errno);
break;
}
x=x+valread;
}
if(x>0)
{
printf("%x",buffer);
}
else
{
printf("ops no read\n");
}
return 0;
}
char buffer[length-1];
int valread=read(fd,&buffer[x],length);
That is a very bad idea. You allocate enough space for length - 1 bytes then attempt to read length bytes into that space.
If the read gets the largest possible size, you will have a buffer overflow, well into undefined behaviour territory(1).
And, on top of that, you attempt to read length bytes even though you may have already read some in earlier iterations of the loop. You should be:
Using the correct length for the buffer; and
Adjusting the length down based on what you've already read.
And, though this may not be a problem, one meg is quite a lot of data to put on the stack (which is often limited in size by default). If that is the case, you may be better of using malloc to get a dynamic buffer, such as:
char *buffer = malloc(length);
// make sure buffer != NULL, then use it.
free(buffer);
So, something like (untested but you should hopefully get the idea):
int x = 0, length = 1024000; // with malloc if needed.
char buffer[length];
while (x < length) {
int valread = read(fd, &buffer[x], length - x);
if (valread == 0) {
printf("zero bytes read\n");
break;
}
else if (valread < 0) {
printf("read return negative %d %d\n",valread,errno);
break;
}
x += valread;
}
(1) An example of what may happen is that overflowing the buffer will affect other variables on the stack in certain ways.
For example, it may corrupt x which would mean your next read could go to some arbitrary place in memory possibly corrupting other things as a result.
Or it could corrupt fd which would make the next read likely to fail with an invalid file descriptor.You can check the actual behaviour by simply printing out those two values before any use. Given the fact you mention "bad file descriptor error", that's possibly the most likely scenario here.
But, to be honest, the best solution is probably just to avoid undefined behaviour (though it may still be educational for you to find out the effects).
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
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 am trying to read a file in C. But when I read, and write it to stdout it prints # also which there is no in my file. What is the reason?
#include <stdio.h>
int main() {
FILE *fp;
int br;
char buffer[10];
int i;
fp = fopen("a.txt","r");
while(1) {
br = fread(buffer,1,10,fp);
printf("%s",buffer);
if (br==0)
break;
}
}
Output:
1234567891#2345678912#3456789
12#3456789
12#
The file:
123456789123456789123456789
Your fread call reads up to 10 bytes correctly, but printf with %s requires string to be null terminated. You can fix it by increasing size of the buffer to be 11 bytes and after every call to fread write zero at the end of data, i.e. buffer[br] = 0;.
The other way to go is to tell printf what is the size of your data by calling printf("%.*s", br, buffer);. You don't need to modify your buffer array then.
Dynamically allocate your buffer and have it be initialized to zeros like this:
char *buffer = calloc(1, 11);
<do your read loop>
free(buffer)
This way you get the zero byte at the end which will terminate the string when printing it. When C prints a string it expects it to be terminated by a NULL (or 0) byte.