How to print content of file after seek - c

I am trying to print the remaining contents of a file after I do a fseek. Right now I am getting nothing returned. What's wrong with my code?
#include <stdio.h>
int main(int argc, char *argv[]){
FILE *fr;
if (fr = fopen (argv[1], "r")){
fseek(fr, 100, SEEK_CUR);
char c[1];
while (fread(c, 1, sizeof(c),fr) > 0)
printf("%s", c);
fclose(fr);
}
else{
perror("File does not exist");
}
}

As the other answers pointed out, you are passing printf a string which may not be NULL terminated. You are also not verifying the file being read is greater than 100 bytes. One last point, in fread() you swapped the size_t size and size_t niters parameters.
Here is an modified version of your program which fixes the above issues (and cleans up the spacing a bit):
#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
FILE *fr;
char c[1];
struct stat sb;
// obtains information about the file
if (stat(argv[1], &sb) == -1)
{
perror("stat()");
return(1);
};
// verifies the file is over 100 bytes in size
if (sb.st_size < 101)
{
fprintf(stderr, "%s: file is less than 100 bytes\n", argv[1]);
return(1);
};
// opens the file, or prints the error and exists
if (!(fr = fopen (argv[1], "r")))
{
perror("fopen():");
return(1);
};
fseek(fr, 100, SEEK_CUR);
while (fread(c, sizeof(c), 1, fr) > 0)
printf("%c", c[0]);
fclose(fr);
return(0);
}
You could also improve the efficiency of reading the file by changing char c[1]; to something line char c[1024]; and updating the while statement to:
while (fread(c, sizeof(char), 1023, fr) > 0)
{
c[1023] = '\0';
printf("%s", c);
};

you cannot print with %s as your string needs to be null terminated and you only have one character.
use:
printf("%c",*c);
not all characters are printable, check an ascii table to see which are printable and which not. eg printing a 0 will not print anything on screen, AFAIK

You are reading a byte but trying to print it with %s, which expects a null-terminated string. Changing that to %c (and of course c to *c so that it agrees with the format string!) should fix things.
Especially if the value of the bytes you read is equal to 0, printf with the %s specifier will output absolutely nothing (as it thinks you are repeatedly asking it to print the empty string).

printf("%s",blabla) should print a null-terminated string. for print one char use printf("%c",c[0]).

Related

Segmentation fault reported in mac terminal

We were supposed to extract strings from a provided file, the output matches the expect, but it reports segmentation fault in the end and I don't know why.
#include<stdio.h>
#include<string.h>
int main(int argc, char *argv[]){
char str[100];
char f;
int len = 0;
FILE *file;
file = fopen(argv[1],"r");
//read only here, so use "r"
if(file==NULL){
printf("The file doesn't exist.\n");
return 1;
}
while(feof(file)==0){
//if feof returns 0 it means it havent reaches the end yet
fread(&f,sizeof(f),1,file);//read in the file
//printabel character between 32 and 126
if(f>=32&&f<=126){
str[len] = f;
len++;
continue;//keep doing it(for ->while)
}
if(strlen(str)>3){
//a string is a run of at least 4
printf("The output is:%s\n",str);
len=0;//reset
memset(str, 0, sizeof(str));
//reset the str so it wont get too big(overflow)
}
}
//close the file and return
fclose(file);
return 0;
}
This is not true
while(feof(file)==0){
//if feof returns 0 it means it havent reaches the end yet
And a very common mistake.
This returns 0 if you have Not read past the end of file. Its s subtle but important detail. Your last read may have read up-to the end of file but not past it. This means there is actually no data left to read but feof() will still return 0.
This is why you must test the result of the read operation.
fread(&f,sizeof(f),1,file);
If this returns zero then you failed to read anything.
Which is why you should structure your loop to test the result of the read (not feof()).
while (fread(&f,sizeof(f),1,file) == 1)
{
// You have successfully read an object from the stream
}
Your code has some fundamental errors:
See Why is while ( !feof (file) ) always wrong?
You don't check if fread returns 0, meaning that no more character could be
read, yet you continue with your algorithm
str is not '\0'-terminated, the strlen(str)>3 yields undefined
behaviour in the first iteration and will likely be evaluated as true right in the first iteration.
Then the printf would also yield undefined behaviour for the same reason.
Don't use the ASCII code directly, it's hard to read, you have to look up in
the ASCII table to see what 32 is and what 126. Better use the character
constants
if(f>= ' ' && f <= '~'){
...
}
This is easier to read and you get the intention of the code immediately.
So the program can be rewritten like this:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]){
char str[100];
char f;
int len = 0;
FILE *file;
file = fopen(argv[1],"r");
//read only here, so use "r"
if(file==NULL){
printf("The file doesn't exist.\n");
return 1;
}
memset(str, 0, sizeof str);
while(fread(&f, sizeof f, 1, file) == 1)
{
if(f >= ' ' && f <= '~')
{
str[len++] = f;
continue;
}
if(strlen(str) > 3) // or if(len > 3)
{
printf("The output is: %s\n", str);
len = 0;
memset(str, 0, sizeof str);
}
}
fclose(file);
return 0;
}

Read file block by block in C

I want to copy the contents of file1 to file2 exactly as they are (keeping spaces and newlines). I specifically want to copy these contents one small block of chars at a time(this is a small segment of a larger project so bear with me).
I have attempted the following:
#include <stdio.h>
#include <stdlib.h>
#define MAX 5
int main(int argc, char *argv[]) {
FILE *fin, *fout;
char buffer[MAX];
int length;
char c;
if((fin=fopen(argv[1], "r")) == NULL){
perror("fopen");
exit(EXIT_FAILURE);
}
if((fout=fopen(argv[2], "w")) == NULL){
perror("fopen");
exit(EXIT_FAILURE);
}
while(1){
length = 0;
while((c = fgetc(fin)) != EOF && length < MAX){
buffer[length++] = (char) c;
}
if(length == 0){
break;
}
fprintf(fout, "%s", buffer);
}
fclose(fout);
fclose(fin);
}
However, this causes incorrect output to my file2. Any input would be appreciated.
Your buffer is not zero-terminated. Use fwrite instead of fprintf:
fwrite(buffer, 1, length, fout);
And you should check the error too. So compare return code of fwrite to length and if it differs, either retry the write of remaining bytes (if positive) or print appropriate error message via perror("fwrite") (if return code is negative).
Additionally you may consider opening the files in binary mode which would cause difference on windows, i.e. pass "rb" and "wb" to fopen.
Last but not least, instead of looping and getting one character at a time, consider using fread instead:
length = fread(buffer, 1, MAX, fin);
Here is a simple example.(with no error checking)
You should use fwrite() since the string you would write to file is not a "null-terminated". And also note that "b" mode is specified with fopen(), which means you want to open the file as a binary file.
#include <stdio.h>
#include <stdlib.h>
#define MAX 5
#define FILE_BLOCK_SIZE 50
int _tmain(int argc, _TCHAR* argv[])
{
FILE *fin, *fout;
unsigned char *BufContent = NULL;
BufContent = (unsigned char*) malloc(FILE_BLOCK_SIZE);
size_t BufContentSz;
if((fin=fopen("E:\\aa.txt", "rb")) == NULL){
perror("fopen");
exit(EXIT_FAILURE);
}
if((fout=fopen("E:\\bb.txt", "wb")) == NULL){
perror("fopen");
exit(EXIT_FAILURE);
}
while ((BufContentSz = fread(BufContent, sizeof(unsigned char), FILE_BLOCK_SIZE, fin)) > 0)
{
fwrite(BufContent, sizeof(unsigned char), BufContentSz, fout);
}
fclose(fout);
fclose(fin);
delete BufContent;
return 0;
}
First off, change char buffer[MAX]; to int buffer[MAX];, and char c; to int c;, for a char can be either signed char or unsigned char, depending on your implementation. In the later case, c = EOF will give c a large positive number(It's unsigned ,anyway), so the loop will never end. A int will be large enough to hold all characters and EOF though.
Then, change your
fprintf(fout, "%s", buffer);
to
fwrite(buffer, 1, length, four);
This is because fprintf(fout, "%s", buffer); call for a C-style string, with ends with a '\0', but your buffer isn't zero-terminated. As a result, the program will keep copying the stuff in the stack, until a '\0' is met, leaving lots of garbage in file2.

fread is not reading other file formats

I am fairly new to C still, but the program below compiles just fine, (using gcc) and it even works when using text files, but I when I use other file formats, i.e. png, I get nothing. The console spits out ?PNG and nothing else. I don't want the image to print as an image, obviously the program does nothing like that, but I would like the data from the png file to be printed. Why is the program not fread-ing properly? Is is because fread refuses any file other than text?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE *fp;
int main() {
char buffer[1000];
fp=fopen("FILE IN QUESTION HERE", "rb");
if(fp==NULL) {
perror("An error occured while opening the file...");
exit(1);
}
fread(buffer, 1000, 1, fp);
printf("%s\n", buffer);
fclose(fp);
return 0;
}
%s in printf() is for printing null-terminated string, not binary data and PNG header contains a signature to prevent the data from being transfered as text by mistake.
(Actually there are no 0x00 in the PNG signature and printf() stopped at the 0x00 contained in the size of IHDR chunk)
Use fwrite() to output binary data, or print the bytes one-by-one via putchar().
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
FILE* fp; /* avoid using gloval variables unless it is necessary */
char buffer[1000] = {0}; /* initialize to avoid undefined behavior */
fp=fopen("FILE IN QUESTION HERE", "rb");
if(fp==NULL) {
perror("An error occured while opening the file...");
exit(1);
}
fread(buffer, 1000, 1, fp);
fwrite(buffer, 1000, 1, stdout); /* use fwrite instead of printf */
fclose(fp);
return 0;
}
fread is not reading other file formats
Code does not check the result of fread(). That is the way to determine if fread() is working.
char buffer[1000];
// fread(buffer, 1000, 1, fp);
size_t sz = fread(buffer, 1000, 1, fp);
if (sz == 0) puts("Did not read an entire block");
fread() returns the number of blocks read. With OP's case, code is attempting to read one 1000 byte block. Recommend reading 1000 blocks, each of 1 char rather than 1 block of a 1000 char. Further, avoid magic numbers.
for (;;) {
size_t sz = fread(buffer, sizeof buffer[0], sizeof buffer, fp);
if (sz == 0) break;
// Somehow print the buffer.
print_it(buffer, sz);
}
OP call to printf() expects a pointer to a string. A C string is an array of characters up to and including the terminating null character. buffer may/may not contain a null character and useful data after a null character.
// Does not work for OP
// printf("%s\n", buffer);
The data of a .png file is mostly binary and will have little textual meaning. A sample print function of mixed binary data and text follows. Most output will appears meaningless until one learns the .png file format. Untested code.
int print_it(const unsigned char *x, size_t sz) {
char buf[5];
unsigned column = 0;
while (sz > 0) {
sz--;
if (isgraph(*x) && *x != `(`) {
sprintf(buf, "%c", *x);
} else {
sprintf(buf, "(%02X)", *x);
}
column += strlen(buf);
if (column > 80) {
column = 0;
fputc('\n', stdout);
}
fputs(buf, stdout);
}
if (column > 0) fputc('\n', stdout);
}

How can i select the last line of a text file using C

I am trying to find out a way to select the last line of a text file using C (not c++ or c#, just C) and I am having a difficult time finding a way to do this, if anyone could assist me with this problem I would be very grateful, thanks! (btw for a good example of what i am trying to do, this would be similar what to tail -n 1 would be doing in bash)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main(int argc, char *argv[])
{
FILE *fd; // File pointer
char filename[] = "./Makefile"; // file to read
char buff[1024];
if ((fd = fopen(filename, "r")) != NULL) // open file
{
fseek(fd, 0, SEEK_SET); // make sure start from 0
while(!feof(fd))
{
memset(buff, 0x00, 1024); // clean buffer
fscanf(fd, "%[^\n]\n", buff); // read file *prefer using fscanf
}
printf("Last Line :: %s\n", buff);
}
}
I'm using Linux.
CMIIW
No direct way, but my preferred method is:
Go to the end of the file
Read last X bytes
If they contain '\n' - you got your line - read from that offset to the end of the file
Read X bytes before them
back to 3 until match found
If reached the beginning of the file - the whole file is the last line
E.g.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef max
#define max(a, b) ((a)>(b))? (a) : (b)
#endif
long GetFileSize(FILE *fp){
long fsize = 0;
fseek(fp,0,SEEK_END);
fsize = ftell(fp);
fseek(fp,0,SEEK_SET);//reset stream position!!
return fsize;
}
char *lastline(char *filepath){
FILE *fp;
char buff[4096+1];
int size,i;
long fsize;
if(NULL==(fp=fopen(filepath, "r"))){
perror("file cannot open at lastline");
return NULL;
}
fsize= -1L*GetFileSize(fp);
if(size=fseek(fp, max(fsize, -4096L), SEEK_END)){
perror("cannot seek");
exit(1);
}
size=fread(buff, sizeof(char), 4096, fp);
fclose(fp);
buff[size] = '\0';
i=size-1;
if(buff[i]=='\n'){
buff[i] = '\0';
}
while(i >=0 && buff[i] != '\n')
--i;
++i;
return strdup(&buff[i]);
}
int main(void){
char *last;
last = lastline("data.txt");
printf("\"%s\"\n", last);
free(last);
return 0;
}
If you are using *nix operating system, you can use the command 'last'. See 'last' man page for details.
If you want integrate the functionality inside another program, you can use 'system' call to execute 'last' and get it's result.
A simple and inefficient way to do it is to read each line into a buffer.
When the last read gives you EOF, you have the last line in the buffer.
Binyamin Sharet's suggestion is more efficient, but just a bit harder to implement.

fgets to read particular size

I'm trying to write a program that reads a certain amount of characters from a file name given from command line. Here is what I have:
#include <stdio.h>
int main(int argc, char **argv)
{
int i = 0;
FILE *f;
char* fileName = argv[1];
char buf[40];
f = fopen(fileName, "r");
while(!feof(f)){
fgets(buf, 10, f);
printf("%s\n", buf);
}
fclose(f);
return 1;
}
Say in this particular case I need first 10 chars, then the next 10 chars, etc until the file is over. However, when I run this code it doesn't actually give me the right output. I tried 11 as well since the documentation said fgets() reads n-1 characters, but that doesn't work either. Some stuff at the beginning is read, but nothing afterwards is and it just gives me a bunch of blanks. Any idea what is wrong?
Thanks
The function you are looking for is fread, like this:
fread(buf, 10, 1, f);
It works almost ok if you remove the \n from your printf format string (assuming that you want to basically echo a whole file as is).
I would also loop based on fgets(...) != NULL since feof() will return a true value after fgets errors and hits EOF, so your last buffer-full will be printed twice. You could make a small change to your code as so:
#include <stdio.h>
int main(int argc, char **argv)
{
int i = 0;
FILE *f;
char* fileName = argv[1];
char buf[40];
f = fopen(fileName, "r");
while(fgets(buf, 10, f))
printf("%s", buf);
fclose(f);
return 0;
}
Also, as others have stated, while I took too long to answer, fread may be a better alternative since fgets won't necessarily read 10 chars; it'll stop at every newline and you don't care about reading a line at a time.
fgets is intended to read a line, up to a maximum length. If you want to read 10 characters at a time, regardless of line breaks, you probably want to use fread instead:
Either way, you definitely do not want to use while (!feof(f)). You probably want something like:
int main(int argc, char **argv) {
char buf[40];
FILE *f;
if (NULL == (f=fopen(argv[1], "r"))) {
fprintf(stderr, "Unable to open file\n");
return EXIT_FAILURE;
}
size_t len;
while (0 < (len=fread(buf, 10, 1, f)))
printf("%*.*s\n", len, len, buf);
return 0;
}

Resources