read a file line by line with POSIX IO primitives - c

I'm a newbie and I'm trying to implement my own readline() with POSIX IO primitives.
I've wrote the code:
int readline(int fd, char **line, size_t size)
{
char *ch = malloc(sizeof(char));
char buf[BUFSIZ];
int index = 0;
int nr;
if (NULL == line)
return -1;
do
{
nr = read(fd, ch, 1);
if (nr == -1)
{
perror("read()");
return -1;
} else
if (0 == nr)
break;
buf[index++] = (*ch);
} while ((*ch != '\n') && (index < BUFSIZ));
if ((index) && (buf[index-1] == '\r'))
{
index--;
}
buf[index++] = '\n';
buf[index] = 0; /* null-terminate */
printf("index = %d\n", index);
strncpy(*line, buf, size);
if ((buf[0] == '\n') || (buf[0] == '\0') || (buf[0] == '\r'))
return 0;
return index;
}
int main(void)
{
int fd;
ssize_t nbytes;
char *line = malloc(BUFSIZ*sizeof(char));
fd = open("/etc/passwd", O_RDONLY);
while((nbytes = readline(fd, &line, sizeof(line))) > 0)
{
write(1, line, nbytes);
}
close(fd);
return 0;
}
But it reads only 8 characters of each line. I spent much time to fix the code, but didn't get anywhere. I also read many topics on this website, most of them use the same algorithm, but it is only my code that does not work!

The problem is your use of the sizeof operator to get the size of the allocate memory. The sizeof operator will not give you the size of what a pointer points to, it will give you the size of the actual pointer.
In your case, it's 8 bytes which equals 64 bits, which is the standard pointer size on 64-bit systems.
You need to keep track of the sizes you allocate yourself, and in this case pass BUFSIZ as the argument instead.

Related

zsh: segmentation fault when reading a file in c [duplicate]

I wrote this function to read a line from a file:
const char *readLine(FILE *file) {
if (file == NULL) {
printf("Error: file pointer is null.");
exit(1);
}
int maximumLineLength = 128;
char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);
if (lineBuffer == NULL) {
printf("Error allocating memory for line buffer.");
exit(1);
}
char ch = getc(file);
int count = 0;
while ((ch != '\n') && (ch != EOF)) {
if (count == maximumLineLength) {
maximumLineLength += 128;
lineBuffer = realloc(lineBuffer, maximumLineLength);
if (lineBuffer == NULL) {
printf("Error reallocating space for line buffer.");
exit(1);
}
}
lineBuffer[count] = ch;
count++;
ch = getc(file);
}
lineBuffer[count] = '\0';
char line[count + 1];
strncpy(line, lineBuffer, (count + 1));
free(lineBuffer);
const char *constLine = line;
return constLine;
}
The function reads the file correctly, and using printf I see that the constLine string did get read correctly as well.
However, if I use the function e.g. like this:
while (!feof(myFile)) {
const char *line = readLine(myFile);
printf("%s\n", line);
}
printf outputs gibberish. Why?
If your task is not to invent the line-by-line reading function, but just to read the file line-by-line, you may use a typical code snippet involving the getline() function (see the manual page here):
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE * fp;
char * line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("/etc/motd", "r");
if (fp == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, fp)) != -1) {
printf("Retrieved line of length %zu:\n", read);
printf("%s", line);
}
fclose(fp);
if (line)
free(line);
exit(EXIT_SUCCESS);
}
FILE* filePointer;
int bufferLength = 255;
char buffer[bufferLength]; /* not ISO 90 compatible */
filePointer = fopen("file.txt", "r");
while(fgets(buffer, bufferLength, filePointer)) {
printf("%s\n", buffer);
}
fclose(filePointer);
In your readLine function, you return a pointer to the line array (Strictly speaking, a pointer to its first character, but the difference is irrelevant here). Since it's an automatic variable (i.e., it's “on the stack”), the memory is reclaimed when the function returns. You see gibberish because printf has put its own stuff on the stack.
You need to return a dynamically allocated buffer from the function. You already have one, it's lineBuffer; all you have to do is truncate it to the desired length.
lineBuffer[count] = '\0';
realloc(lineBuffer, count + 1);
return lineBuffer;
}
ADDED (response to follow-up question in comment): readLine returns a pointer to the characters that make up the line. This pointer is what you need to work with the contents of the line. It's also what you must pass to free when you've finished using the memory taken by these characters. Here's how you might use the readLine function:
char *line = readLine(file);
printf("LOG: read a line: %s\n", line);
if (strchr(line, 'a')) { puts("The line contains an a"); }
/* etc. */
free(line);
/* After this point, the memory allocated for the line has been reclaimed.
You can't use the value of `line` again (though you can assign a new value
to the `line` variable if you want). */
//open and get the file handle
FILE* fh;
fopen_s(&fh, filename, "r");
//check if file exists
if (fh == NULL){
printf("file does not exists %s", filename);
return 0;
}
//read line by line
const size_t line_size = 300;
char* line = malloc(line_size);
while (fgets(line, line_size, fh) != NULL) {
printf(line);
}
free(line); // dont forget to free heap memory
A complete, fgets() solution:
#include <stdio.h>
#include <string.h>
#define MAX_LEN 256
int main(void)
{
FILE* fp;
fp = fopen("file.txt", "r");
if (fp == NULL) {
perror("Failed: ");
return 1;
}
char buffer[MAX_LEN];
while (fgets(buffer, MAX_LEN, fp))
{
// Remove trailing newline
buffer[strcspn(buffer, "\n")] = 0;
printf("%s\n", buffer);
}
fclose(fp);
return 0;
}
Output:
First line of file
Second line of file
Third (and also last) line of file
Remember, if you want to read from Standard Input (rather than a file as in this case), then all you have to do is pass stdin as the third parameter of fgets() method, like this:
while(fgets(buffer, MAX_LEN, stdin))
Appendix
Removing trailing newline character from fgets() input
how to detect a file is opened or not in c
readLine() returns pointer to local variable, which causes undefined behaviour.
To get around you can:
Create variable in caller function and pass its address to readLine()
Allocate memory for line using malloc() - in this case line will be persistent
Use global variable, although it is generally a bad practice
Use fgets() to read a line from a file handle.
Some things wrong with the example:
you forgot to add \n to your printfs. Also error messages should go to stderr i.e. fprintf(stderr, ....
(not a biggy but) consider using fgetc() rather than getc(). getc() is a macro, fgetc() is a proper function
getc() returns an int so ch should be declared as an int. This is important since the comparison with EOF will be handled correctly. Some 8 bit character sets use 0xFF as a valid character (ISO-LATIN-1 would be an example) and EOF which is -1, will be 0xFF if assigned to a char.
There is a potential buffer overflow at the line
lineBuffer[count] = '\0';
If the line is exactly 128 characters long, count is 128 at the point that gets executed.
As others have pointed out, line is a locally declared array. You can't return a pointer to it.
strncpy(count + 1) will copy at most count + 1 characters but will terminate if it hits '\0' Because you set lineBuffer[count] to '\0' you know it will never get to count + 1. However, if it did, it would not put a terminating '\0' on, so you need to do it. You often see something like the following:
char buffer [BUFFER_SIZE];
strncpy(buffer, sourceString, BUFFER_SIZE - 1);
buffer[BUFFER_SIZE - 1] = '\0';
if you malloc() a line to return (in place of your local char array), your return type should be char* - drop the const.
Here is my several hours... Reading whole file line by line.
char * readline(FILE *fp, char *buffer)
{
int ch;
int i = 0;
size_t buff_len = 0;
buffer = malloc(buff_len + 1);
if (!buffer) return NULL; // Out of memory
while ((ch = fgetc(fp)) != '\n' && ch != EOF)
{
buff_len++;
void *tmp = realloc(buffer, buff_len + 1);
if (tmp == NULL)
{
free(buffer);
return NULL; // Out of memory
}
buffer = tmp;
buffer[i] = (char) ch;
i++;
}
buffer[i] = '\0';
// Detect end
if (ch == EOF && (i == 0 || ferror(fp)))
{
free(buffer);
return NULL;
}
return buffer;
}
void lineByline(FILE * file){
char *s;
while ((s = readline(file, 0)) != NULL)
{
puts(s);
free(s);
printf("\n");
}
}
int main()
{
char *fileName = "input-1.txt";
FILE* file = fopen(fileName, "r");
lineByline(file);
return 0;
}
const char *readLine(FILE *file, char* line) {
if (file == NULL) {
printf("Error: file pointer is null.");
exit(1);
}
int maximumLineLength = 128;
char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);
if (lineBuffer == NULL) {
printf("Error allocating memory for line buffer.");
exit(1);
}
char ch = getc(file);
int count = 0;
while ((ch != '\n') && (ch != EOF)) {
if (count == maximumLineLength) {
maximumLineLength += 128;
lineBuffer = realloc(lineBuffer, maximumLineLength);
if (lineBuffer == NULL) {
printf("Error reallocating space for line buffer.");
exit(1);
}
}
lineBuffer[count] = ch;
count++;
ch = getc(file);
}
lineBuffer[count] = '\0';
char line[count + 1];
strncpy(line, lineBuffer, (count + 1));
free(lineBuffer);
return line;
}
char linebuffer[256];
while (!feof(myFile)) {
const char *line = readLine(myFile, linebuffer);
printf("%s\n", line);
}
note that the 'line' variable is declared in calling function and then passed, so your readLine function fills predefined buffer and just returns it. This is the way most of C libraries work.
There are other ways, which I'm aware of:
defining the char line[] as static
(static char line[MAX_LINE_LENGTH]
-> it will hold it's value AFTER returning from the function). -> bad,
the function is not reentrant, and
race condition can occur -> if you
call it twice from two threads, it
will overwrite it's results
malloc()ing the char line[], and
freeing it in calling functions ->
too many expensive mallocs, and,
delegating the responsibility to free the buffer to another function (the most elegant solution is to call malloc and free on any buffers in same function)
btw, 'explicit' casting from char* to const char* is redundant.
btw2, there is no need to malloc() the lineBuffer, just define it char lineBuffer[128], so you don't need to free it
btw3 do not use 'dynamic sized stack arrays' (defining the array as char arrayName[some_nonconstant_variable]), if you don't exactly know what are you doing, it works only in C99.
void readLine(FILE* file, char* line, int limit)
{
int i;
int read;
read = fread(line, sizeof(char), limit, file);
line[read] = '\0';
for(i = 0; i <= read;i++)
{
if('\0' == line[i] || '\n' == line[i] || '\r' == line[i])
{
line[i] = '\0';
break;
}
}
if(i != read)
{
fseek(file, i - read + 1, SEEK_CUR);
}
}
what about this one?
Implement method to read, and get content from a file (input1.txt)
#include <stdio.h>
#include <stdlib.h>
void testGetFile() {
// open file
FILE *fp = fopen("input1.txt", "r");
size_t len = 255;
// need malloc memory for line, if not, segmentation fault error will occurred.
char *line = malloc(sizeof(char) * len);
// check if file exist (and you can open it) or not
if (fp == NULL) {
printf("can open file input1.txt!");
return;
}
while(fgets(line, len, fp) != NULL) {
printf("%s\n", line);
}
free(line);
}
Hope this help. Happy coding!
You should use the ANSI functions for reading a line, eg. fgets. After calling you need free() in calling context, eg:
...
const char *entirecontent=readLine(myFile);
puts(entirecontent);
free(entirecontent);
...
const char *readLine(FILE *file)
{
char *lineBuffer=calloc(1,1), line[128];
if ( !file || !lineBuffer )
{
fprintf(stderr,"an ErrorNo 1: ...");
exit(1);
}
for(; fgets(line,sizeof line,file) ; strcat(lineBuffer,line) )
{
if( strchr(line,'\n') ) *strchr(line,'\n')=0;
lineBuffer=realloc(lineBuffer,strlen(lineBuffer)+strlen(line)+1);
if( !lineBuffer )
{
fprintf(stderr,"an ErrorNo 2: ...");
exit(2);
}
}
return lineBuffer;
}
My implement from scratch:
FILE *pFile = fopen(your_file_path, "r");
int nbytes = 1024;
char *line = (char *) malloc(nbytes);
char *buf = (char *) malloc(nbytes);
size_t bytes_read;
int linesize = 0;
while (fgets(buf, nbytes, pFile) != NULL) {
bytes_read = strlen(buf);
// if line length larger than size of line buffer
if (linesize + bytes_read > nbytes) {
char *tmp = line;
nbytes += nbytes / 2;
line = (char *) malloc(nbytes);
memcpy(line, tmp, linesize);
free(tmp);
}
memcpy(line + linesize, buf, bytes_read);
linesize += bytes_read;
if (feof(pFile) || buf[bytes_read-1] == '\n') {
handle_line(line);
linesize = 0;
memset(line, '\0', nbytes);
}
}
free(buf);
free(line);
Provide a portable and generic getdelim function, test passed via msvc, clang, gcc.
/*
* An implementation conform IEEE Std 1003.1-2017:
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html
*
* <nio.h>:
* https://github.com/junjiemars/c/blob/c425bd0e49df35a2649327664d3f6cd610791996/src/posix/nio.h
* <nio.c>:
* https://github.com/junjiemars/c/blob/c425bd0e49df35a2649327664d3f6cd610791996/src/posix/nio.c
*
*/
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
/*
* LINE_MAX dependents on OS' implementations so check it first.
* https://github.com/junjiemars/c/blob/c425bd0e49df35a2649327664d3f6cd610791996/src/posix/nlim_auto_check
*/
#define NM_LINE_MAX 4096 /* Linux */
#if (MSVC)
typedef SSIZE_T ssize_t;
# if !defined(SSIZE_MAX)
# define SSIZE_MAX ((ssize_t)((size_t)((ssize_t)-1) >> 1))
# endif
#endif
ssize_t getdelim(char **restrict lineptr, size_t *restrict n, int delimiter,
FILE *restrict stream);
#if defined(getline)
# undef getline
#endif
#define getline(lp, n, f) getdelim((lp), (n), 0x0a, (f))
ssize_t
getdelim(char **restrict lineptr, size_t *restrict n, int delimiter,
FILE *restrict stream)
{
int c;
char *p, *p1;
ssize_t len;
if (NULL == lineptr || NULL == n || NULL == stream
|| (UCHAR_MAX < delimiter || delimiter < 0))
{
errno = EINVAL;
return EOF;
}
if (feof(stream) || ferror(stream))
{
return EOF;
}
if (0 == *lineptr)
{
if (0 == *n)
{
*n = NM_LINE_MAX;
}
*lineptr = malloc(*n);
if (0 == *lineptr)
{
return EOF;
}
}
p = *lineptr;
len = 0;
while (EOF != (c = fgetc(stream)))
{
if (SSIZE_MAX == (ssize_t) len)
{
errno = EOVERFLOW;
return EOF;
}
if ((size_t) len == (*n - 1))
{
*n <<= 1;
p1 = realloc(*lineptr, *n);
if (0 == p1)
{
return EOF;
}
*lineptr = p1;
p = p1 + len;
}
*p++ = (char) c;
len++;
if (c == delimiter)
{
break;
}
}
if (ferror(stream))
{
return EOF;
}
*p = 0;
return len;
}
int
main(void)
{
FILE *fp;
char *line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("/some-file", "r");
if (fp == NULL)
exit(1);
while ((read = getline(&line, &len, fp)) != -1) {
printf("Retrieved line of length %zu :\n", read);
printf("%s", line);
}
if (ferror(fp)) {
/* handle error */
}
free(line);
fclose(fp);
return 0;
}
You make the mistake of returning a pointer to an automatic variable.
The variable line is allocated in the stack and only lives as long as the function lives.
You are not allowed to return a pointer to it, because as soon as it returns the memory will be given elsewhere.
const char* func x(){
char line[100];
return (const char*) line; //illegal
}
To avoid this, you either return a pointer to memory which resides on the heap eg. lineBuffer
and it should be the user's responsibility to call free() when he is done with it.
Alternatively you can ask the user to pass you as an argument a memory address on which to write the line contents at.
I want a code from ground 0 so i did this to read the content of dictionary's word line by line.
char temp_str[20]; // you can change the buffer size according to your requirements And A single line's length in a File.
Note I've initialized the buffer With Null character each time I read line.This function can be Automated But Since I need A proof of Concept and want to design a programme Byte By Byte
#include<stdio.h>
int main()
{
int i;
char temp_ch;
FILE *fp=fopen("data.txt","r");
while(temp_ch!=EOF)
{
i=0;
char temp_str[20]={'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'};
while(temp_ch!='\n')
{
temp_ch=fgetc(fp);
temp_str[i]=temp_ch;
i++;
}
if(temp_ch=='\n')
{
temp_ch=fgetc(fp);
temp_str[i]=temp_ch;
}
printf("%s",temp_str);
}
return 0;
}

Problem with printing first 10 rows of a file

So I am trying to make a function print_file_rows() that prints the first ten rows of a file. If the file has more than 10 rows it works perfectly fine but if there's 10 or less it starts printing garbage. Any ideas on how I can fix this? (MUST ONLY USE THE SYSTEM FUNCTIONS OPEN/READ/WRITE/CLOSE)
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
void print_file_rows(char *path)
{
int fd = open(path, O_RDONLY);
if (fd < 0)
{
return NULL;
}
size_t size = 100;
size_t offset = 0;
size_t res;
char *buff = malloc(size);
while((res = read(fd, buff + offset, 100)) != 0)
{
offset += res;
if (offset + 100 > size)
{
size *= 2;
buff = realloc(buff, size);
}
}
close(fd);
int j = 0;
for(int i = 0;buff[i] != '\0'; i++)
{
if(j == 10)
{
break;
}
if(buff[i] == '\n')
{
j++;
}
printf("%c", buff[i]);
}
free(buff);
}
int main()
{
print_file_rows("a.txt");
return 0;
}
You do not need any buffers. It is most likely buffered on the OS level so you may print char by char.
int print_file_rows(char *path, size_t nrows)
{
int result = -1;
int fd = open(path, O_RDONLY);
char c;
if (fd > 0)
{
while(nrows && read(fd, &c, 1) == 1)
{
write(STDOUT_FILENO, &c, 1);
if(c == `\n`) nrows--;
}
result = nrows;
}
close(fd);
return result;
}
int main()
{
if(print_file_rows("a.txt", 10) == -1)
printf("Something has gone wrong\n");
return 0;
}
From man 2 read:
SYNOPSIS
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
DESCRIPTION
read() attempts to read up to count bytes from file descriptor fd into the buffer starting at buf.
read is for reading raw bytes, and as such has no notion of strings. It does not place a NUL terminating byte ('\0') at the end of the buffer. If you are going to treat the data you read as a string, you must terminate the buffer yourself.
To make room for this NUL terminating byte you should always allocate one extra byte in your buffer (i.e., read one less byte that your maximum).
We can see the return value is actually of type ssize_t, rather than size_t, which allows for
On error, -1 is returned, and errno is set to indicate the error.
This means we will need to check that the return value is greater than zero, rather than not zero which would cause the offset to be decremented on error.
With all that said, note that this answer from a similar question posted just yesterday shows how to achieve this without the use of a dynamic buffer. You can simply read the file one byte at a time and stop reading when you've encountered 10 newline characters.
If you do want to understand how to read a file into a dynamic buffer, then here is an example using the calculated offset to NUL terminate the buffer as it grows. Note that reading the entire file this way is inefficient for this task (especially for a large file).
(Note: the call to write, instead of printf)
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
void print_file_rows(const char *path)
{
int fd = open(path, O_RDONLY);
const size_t read_size = 100;
size_t size = read_size;
size_t offset = 0;
ssize_t res;
char *buff = malloc(size + 1);
while ((res = read(fd, buff + offset, read_size)) > 0) {
offset += res;
buff[offset] = '\0';
if (offset + read_size > size) {
size *= 2;
buff = realloc(buff, size + 1);
}
}
close(fd);
int lines = 0;
for (size_t i = 0; lines < 10 && buff[i] != '\0'; i++) {
write(STDOUT_FILENO, &buff[i], 1);
if (buff[i] == '\n')
lines++;
}
free(buff);
}
int main(void)
{
print_file_rows("a.txt");
}
(Error handling omitted for code brevity. malloc, realloc, and open can all fail, and should normally be handled.)

Weird behaviour of FIFO reading/writing in C

I've got a C program that reproduces a server using FIFOs. The program reads two lines from an input FIFO — a number n and a string str— and writes on an output FIFO n lines, each of which is a single occurrence of str. I wrote the following code.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define MAX_SIZE 256
char *readline(int fd, char *buffer) {
char c;
int i = 0;
while (read(fd, &c, 1) != 0) {
if (c == '\n')
break;
buffer[i++] = c;
}
return buffer;
}
int main(int argc, char** argv) {
mkfifo(argv[1], 0666);
mkfifo(argv[2], 0666);
int in = open(argv[1], O_RDONLY);
int out = open(argv[2] ,O_WRONLY);
char line[MAX_SIZE];
memset(line, 0, MAX_SIZE);
int n, i;
while (1) {
strcpy(line, readline(in, line));
sscanf(line, "%d", &n);
strcpy(line, readline(in, line));
for (i = 0; i < n; i++) {
write(out, line, strlen(line));
write(out, "\n", 1);
}
}
close(in);
close(out);
return 0;
}
This program compiles and runs with no errors, but it outputs a different number of occurrences of the string at each execution. For example, if the two input lines in the input FIFO are 5\nhello, it then prints out from 1 to 25 occurrences of hello at each run (frequency appears to be completely random).
I've been stuck on this for two days. Please give me some help.
I make no claims or warrants that I even know what your program does, as it has been 20 years since I had any pressing need to work with FIFO's at the system level. But one thing is clear. Two days is a long time to work on something without ever running it in a debugger, of which doing so would have exposed a number of problems.
First, readline() never terminates the string it is passed. This isn't as important the first time around as the second and beyond, since shorter data may be present in the input lines. Furthermore, read() can fail, and in doing so does not return 0, the only condition on your loop which will break. That failure should break the loop and be reflected in the return result. Because you return the buffer pointer, a reasonable failure-result could be NULL:
Consider something like this:
char *readline(int fd, char *buffer)
{
ssize_t res = 0;
char c = 0;
int i = 0;
for(;;)
{
res = read(fd, &c, 1);
if (res < 0)
return NULL;
else if (res == 0 || c == '\n')
break;
buffer[i++] = c;
};
buffer[i] = 0;
return buffer;
}
One could argue that it should return NULL if the buffer is empty, since you can't put a 0-length packet on a FIFO. I leave that for you to decide, but it is a potential hole in your algorithm, to be sure.
Next the strcpy() function has undefined behavior if the buffers submitted overlap. Since readline() returns the very buffer that was passed in, and since said-same buffer is also the target of strcpy() is the same buffer, your program is executing UB. From all that I see, strcpy() is useless in this program in the first place, and shouldn't even be there at all.
This is clearly wrong:
strcpy(line, readline(in, line));
sscanf(line, "%d", &n);
strcpy(line, readline(in, line));
for (i = 0; i < n; i++) {
write(out, line, strlen(line));
write(out, "\n", 1);
}
The above should be this:
if (readline(in, line))
{
if (sscanf(line, "%d", &n) == 1)
{
if (readline(in, line))
{
for (i = 0; i < n; i++)
{
write(out, line, strlen(line));
write(out, "\n", 1);
}
}
}
}
assuming the changes to readline() as prescribed were made. These could be combined into a single three-expression if-clause, but as written above it is at-least debuggable. In other words, via short-circuit eval there should be no problems doing this:
if (readline(in, line) &&
sscanf(line, "%d", &n) == 1 &&
readline(in, line))
{
for (i = 0; i < n; i++)
{
write(out, line, strlen(line));
write(out, "\n", 1);
}
}
but I would advise you keep the former until you have thoroughly debugged this.
Finally, note that readline() is still a buffer overflow just waiting to happen. You really should pass a max-len to that function and limit that potential possibility, or dynamically manage the buffer.
The code does not initalises line for each iteration, so if readline() does not read anything it leaves line's content untouched.
And you do not test whether sscanf() fails, the code does not recognize als n is left unchanged and the last value of line get printed out n times and everything starts over again ...
Also readline() misses to check whether read() failed.
To learn from this exercise it to always test the result of a (system) call whether it failed or not.
int readline(int fd, char *buf, int nbytes) {
int numread = 0;
int value; /* read fonksiyonu sonunda okunan sayı degerini gore islem yapar */
/* Controls */
while (numread < nbytes - 1) {
value = read(fd, buf + numread, 1);
if ((value == -1) && (errno == EINTR))
continue;
if ( (value == 0) && (numread == 0) )
return 0;
if (value == 0)
break;
if (value == -1)
return -1;
numread++;
/* realocating for expand the buffer ...*/
if( numread == allocSize-2 ){
allocSize*=2; /* allocSize yeterli olmadıgı zaman buf ı genisletmemizi saglayarak
memory leak i onler */
buf=realloc(buf,allocSize);
if( buf == NULL ){
fprintf(stderr,"Failed to reallocate!\n");
return -1;
}
}
/* Eger gelen karakter \n ise return okudugu karakter sayısı */
if (buf[numread-1] == '\n') {
buf[numread] = '\0';
return numread;
}
}
errno = EINVAL;
return -1;
}

fprintf failing, but fputc works just fine?

I am trying to write a function that reads a line of text over a socket (it's part of the code I am writing for an HTTP Server for homework).
It works just fine writing to a file when I am writing using fputc. However, when I try and copy the characters to a buffer, and then use fprintf to print the whole buffer to the file, I don't seem to be getting any output.
Here's the code:
int read_line(int fd, char *buffer, int size) {
char *broken_buffer = (char*) malloc(sizeof(char) * 8096);
char next = '\0';
char err;
int i = 0;
FILE *f = fopen("read_line2.txt", "w");
while (i < size - 1 && next != '\n') {
err = read(fd, &next, 1);
if (err > 0) {
if (next == '\r') {
err = recv(fd, &next, 1, MSG_PEEK);
if (err > 0 && next == '\n') {
read(fd, &next, 1);
} else {
next = '\n';
}
}
fputc(next, f); // Works
broken_buffer[i] = next;
buffer[i] = next;
i++;
} else {
next = '\n';
}
}
broken_buffer[i] = '\0';
buffer[i] = '\0';
FILE *out = fopen("read_line.txt", "w");
fprintf(out, "%s\n", broken_buffer); // Does not work
fclose(out);
fclose(f);
return i;
}
EDIT: I have tried using this alternative function:
int read_socket(int fd, char *buffer, int size) {
int bytes_recvd = 0;
int retries = 0;
int total_recvd = 0;
while (retries < MAX_RETRIES && size > 0 && strstr(buffer, ">") == NULL) {
bytes_recvd = read(fd, buffer, size);
if (bytes_recvd > 0) {
buffer += bytes_recvd;
size -= bytes_recvd;
total_recvd += bytes_recvd;
} else {
retries++;
}
}
if (bytes_recvd >= 0) {
// Last read was not an error, return how many bytes were recvd
return total_recvd;
}
// Last read was an error, return error code
return -1;
}
And I have no problems printing this one out with fprintf.
EDIT2: I have figured out that i is somehow 0 after the loop, so the first character is being overwritten with a '\0'. However, when I put in debugging code to print out the value of i within the loop, I found it being incremented up to 22 (23 being the final value at which the loop breaks). How is this even possible? The resulting string is:
GET /blah.txt HTTP/1.1
Is the value of next ever 0? If it is 0 then that value will go into broken_buffer, which means that fprintf will think it's at the end of a string before you explicitly put the null there yourself.
The problem turned out to be two processes that were both connecting to the server (thanks, Google Chrome...), and both were writing to the same file somehow. The code WAS working correctly.

C read file line by line

I wrote this function to read a line from a file:
const char *readLine(FILE *file) {
if (file == NULL) {
printf("Error: file pointer is null.");
exit(1);
}
int maximumLineLength = 128;
char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);
if (lineBuffer == NULL) {
printf("Error allocating memory for line buffer.");
exit(1);
}
char ch = getc(file);
int count = 0;
while ((ch != '\n') && (ch != EOF)) {
if (count == maximumLineLength) {
maximumLineLength += 128;
lineBuffer = realloc(lineBuffer, maximumLineLength);
if (lineBuffer == NULL) {
printf("Error reallocating space for line buffer.");
exit(1);
}
}
lineBuffer[count] = ch;
count++;
ch = getc(file);
}
lineBuffer[count] = '\0';
char line[count + 1];
strncpy(line, lineBuffer, (count + 1));
free(lineBuffer);
const char *constLine = line;
return constLine;
}
The function reads the file correctly, and using printf I see that the constLine string did get read correctly as well.
However, if I use the function e.g. like this:
while (!feof(myFile)) {
const char *line = readLine(myFile);
printf("%s\n", line);
}
printf outputs gibberish. Why?
If your task is not to invent the line-by-line reading function, but just to read the file line-by-line, you may use a typical code snippet involving the getline() function (see the manual page here):
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE * fp;
char * line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("/etc/motd", "r");
if (fp == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, fp)) != -1) {
printf("Retrieved line of length %zu:\n", read);
printf("%s", line);
}
fclose(fp);
if (line)
free(line);
exit(EXIT_SUCCESS);
}
FILE* filePointer;
int bufferLength = 255;
char buffer[bufferLength]; /* not ISO 90 compatible */
filePointer = fopen("file.txt", "r");
while(fgets(buffer, bufferLength, filePointer)) {
printf("%s\n", buffer);
}
fclose(filePointer);
In your readLine function, you return a pointer to the line array (Strictly speaking, a pointer to its first character, but the difference is irrelevant here). Since it's an automatic variable (i.e., it's “on the stack”), the memory is reclaimed when the function returns. You see gibberish because printf has put its own stuff on the stack.
You need to return a dynamically allocated buffer from the function. You already have one, it's lineBuffer; all you have to do is truncate it to the desired length.
lineBuffer[count] = '\0';
realloc(lineBuffer, count + 1);
return lineBuffer;
}
ADDED (response to follow-up question in comment): readLine returns a pointer to the characters that make up the line. This pointer is what you need to work with the contents of the line. It's also what you must pass to free when you've finished using the memory taken by these characters. Here's how you might use the readLine function:
char *line = readLine(file);
printf("LOG: read a line: %s\n", line);
if (strchr(line, 'a')) { puts("The line contains an a"); }
/* etc. */
free(line);
/* After this point, the memory allocated for the line has been reclaimed.
You can't use the value of `line` again (though you can assign a new value
to the `line` variable if you want). */
//open and get the file handle
FILE* fh;
fopen_s(&fh, filename, "r");
//check if file exists
if (fh == NULL){
printf("file does not exists %s", filename);
return 0;
}
//read line by line
const size_t line_size = 300;
char* line = malloc(line_size);
while (fgets(line, line_size, fh) != NULL) {
printf(line);
}
free(line); // dont forget to free heap memory
A complete, fgets() solution:
#include <stdio.h>
#include <string.h>
#define MAX_LEN 256
int main(void)
{
FILE* fp;
fp = fopen("file.txt", "r");
if (fp == NULL) {
perror("Failed: ");
return 1;
}
char buffer[MAX_LEN];
while (fgets(buffer, MAX_LEN, fp))
{
// Remove trailing newline
buffer[strcspn(buffer, "\n")] = 0;
printf("%s\n", buffer);
}
fclose(fp);
return 0;
}
Output:
First line of file
Second line of file
Third (and also last) line of file
Remember, if you want to read from Standard Input (rather than a file as in this case), then all you have to do is pass stdin as the third parameter of fgets() method, like this:
while(fgets(buffer, MAX_LEN, stdin))
Appendix
Removing trailing newline character from fgets() input
how to detect a file is opened or not in c
readLine() returns pointer to local variable, which causes undefined behaviour.
To get around you can:
Create variable in caller function and pass its address to readLine()
Allocate memory for line using malloc() - in this case line will be persistent
Use global variable, although it is generally a bad practice
Use fgets() to read a line from a file handle.
Some things wrong with the example:
you forgot to add \n to your printfs. Also error messages should go to stderr i.e. fprintf(stderr, ....
(not a biggy but) consider using fgetc() rather than getc(). getc() is a macro, fgetc() is a proper function
getc() returns an int so ch should be declared as an int. This is important since the comparison with EOF will be handled correctly. Some 8 bit character sets use 0xFF as a valid character (ISO-LATIN-1 would be an example) and EOF which is -1, will be 0xFF if assigned to a char.
There is a potential buffer overflow at the line
lineBuffer[count] = '\0';
If the line is exactly 128 characters long, count is 128 at the point that gets executed.
As others have pointed out, line is a locally declared array. You can't return a pointer to it.
strncpy(count + 1) will copy at most count + 1 characters but will terminate if it hits '\0' Because you set lineBuffer[count] to '\0' you know it will never get to count + 1. However, if it did, it would not put a terminating '\0' on, so you need to do it. You often see something like the following:
char buffer [BUFFER_SIZE];
strncpy(buffer, sourceString, BUFFER_SIZE - 1);
buffer[BUFFER_SIZE - 1] = '\0';
if you malloc() a line to return (in place of your local char array), your return type should be char* - drop the const.
Here is my several hours... Reading whole file line by line.
char * readline(FILE *fp, char *buffer)
{
int ch;
int i = 0;
size_t buff_len = 0;
buffer = malloc(buff_len + 1);
if (!buffer) return NULL; // Out of memory
while ((ch = fgetc(fp)) != '\n' && ch != EOF)
{
buff_len++;
void *tmp = realloc(buffer, buff_len + 1);
if (tmp == NULL)
{
free(buffer);
return NULL; // Out of memory
}
buffer = tmp;
buffer[i] = (char) ch;
i++;
}
buffer[i] = '\0';
// Detect end
if (ch == EOF && (i == 0 || ferror(fp)))
{
free(buffer);
return NULL;
}
return buffer;
}
void lineByline(FILE * file){
char *s;
while ((s = readline(file, 0)) != NULL)
{
puts(s);
free(s);
printf("\n");
}
}
int main()
{
char *fileName = "input-1.txt";
FILE* file = fopen(fileName, "r");
lineByline(file);
return 0;
}
const char *readLine(FILE *file, char* line) {
if (file == NULL) {
printf("Error: file pointer is null.");
exit(1);
}
int maximumLineLength = 128;
char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);
if (lineBuffer == NULL) {
printf("Error allocating memory for line buffer.");
exit(1);
}
char ch = getc(file);
int count = 0;
while ((ch != '\n') && (ch != EOF)) {
if (count == maximumLineLength) {
maximumLineLength += 128;
lineBuffer = realloc(lineBuffer, maximumLineLength);
if (lineBuffer == NULL) {
printf("Error reallocating space for line buffer.");
exit(1);
}
}
lineBuffer[count] = ch;
count++;
ch = getc(file);
}
lineBuffer[count] = '\0';
char line[count + 1];
strncpy(line, lineBuffer, (count + 1));
free(lineBuffer);
return line;
}
char linebuffer[256];
while (!feof(myFile)) {
const char *line = readLine(myFile, linebuffer);
printf("%s\n", line);
}
note that the 'line' variable is declared in calling function and then passed, so your readLine function fills predefined buffer and just returns it. This is the way most of C libraries work.
There are other ways, which I'm aware of:
defining the char line[] as static
(static char line[MAX_LINE_LENGTH]
-> it will hold it's value AFTER returning from the function). -> bad,
the function is not reentrant, and
race condition can occur -> if you
call it twice from two threads, it
will overwrite it's results
malloc()ing the char line[], and
freeing it in calling functions ->
too many expensive mallocs, and,
delegating the responsibility to free the buffer to another function (the most elegant solution is to call malloc and free on any buffers in same function)
btw, 'explicit' casting from char* to const char* is redundant.
btw2, there is no need to malloc() the lineBuffer, just define it char lineBuffer[128], so you don't need to free it
btw3 do not use 'dynamic sized stack arrays' (defining the array as char arrayName[some_nonconstant_variable]), if you don't exactly know what are you doing, it works only in C99.
void readLine(FILE* file, char* line, int limit)
{
int i;
int read;
read = fread(line, sizeof(char), limit, file);
line[read] = '\0';
for(i = 0; i <= read;i++)
{
if('\0' == line[i] || '\n' == line[i] || '\r' == line[i])
{
line[i] = '\0';
break;
}
}
if(i != read)
{
fseek(file, i - read + 1, SEEK_CUR);
}
}
what about this one?
Implement method to read, and get content from a file (input1.txt)
#include <stdio.h>
#include <stdlib.h>
void testGetFile() {
// open file
FILE *fp = fopen("input1.txt", "r");
size_t len = 255;
// need malloc memory for line, if not, segmentation fault error will occurred.
char *line = malloc(sizeof(char) * len);
// check if file exist (and you can open it) or not
if (fp == NULL) {
printf("can open file input1.txt!");
return;
}
while(fgets(line, len, fp) != NULL) {
printf("%s\n", line);
}
free(line);
}
Hope this help. Happy coding!
You should use the ANSI functions for reading a line, eg. fgets. After calling you need free() in calling context, eg:
...
const char *entirecontent=readLine(myFile);
puts(entirecontent);
free(entirecontent);
...
const char *readLine(FILE *file)
{
char *lineBuffer=calloc(1,1), line[128];
if ( !file || !lineBuffer )
{
fprintf(stderr,"an ErrorNo 1: ...");
exit(1);
}
for(; fgets(line,sizeof line,file) ; strcat(lineBuffer,line) )
{
if( strchr(line,'\n') ) *strchr(line,'\n')=0;
lineBuffer=realloc(lineBuffer,strlen(lineBuffer)+strlen(line)+1);
if( !lineBuffer )
{
fprintf(stderr,"an ErrorNo 2: ...");
exit(2);
}
}
return lineBuffer;
}
My implement from scratch:
FILE *pFile = fopen(your_file_path, "r");
int nbytes = 1024;
char *line = (char *) malloc(nbytes);
char *buf = (char *) malloc(nbytes);
size_t bytes_read;
int linesize = 0;
while (fgets(buf, nbytes, pFile) != NULL) {
bytes_read = strlen(buf);
// if line length larger than size of line buffer
if (linesize + bytes_read > nbytes) {
char *tmp = line;
nbytes += nbytes / 2;
line = (char *) malloc(nbytes);
memcpy(line, tmp, linesize);
free(tmp);
}
memcpy(line + linesize, buf, bytes_read);
linesize += bytes_read;
if (feof(pFile) || buf[bytes_read-1] == '\n') {
handle_line(line);
linesize = 0;
memset(line, '\0', nbytes);
}
}
free(buf);
free(line);
Provide a portable and generic getdelim function, test passed via msvc, clang, gcc.
/*
* An implementation conform IEEE Std 1003.1-2017:
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html
*
* <nio.h>:
* https://github.com/junjiemars/c/blob/c425bd0e49df35a2649327664d3f6cd610791996/src/posix/nio.h
* <nio.c>:
* https://github.com/junjiemars/c/blob/c425bd0e49df35a2649327664d3f6cd610791996/src/posix/nio.c
*
*/
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
/*
* LINE_MAX dependents on OS' implementations so check it first.
* https://github.com/junjiemars/c/blob/c425bd0e49df35a2649327664d3f6cd610791996/src/posix/nlim_auto_check
*/
#define NM_LINE_MAX 4096 /* Linux */
#if (MSVC)
typedef SSIZE_T ssize_t;
# if !defined(SSIZE_MAX)
# define SSIZE_MAX ((ssize_t)((size_t)((ssize_t)-1) >> 1))
# endif
#endif
ssize_t getdelim(char **restrict lineptr, size_t *restrict n, int delimiter,
FILE *restrict stream);
#if defined(getline)
# undef getline
#endif
#define getline(lp, n, f) getdelim((lp), (n), 0x0a, (f))
ssize_t
getdelim(char **restrict lineptr, size_t *restrict n, int delimiter,
FILE *restrict stream)
{
int c;
char *p, *p1;
ssize_t len;
if (NULL == lineptr || NULL == n || NULL == stream
|| (UCHAR_MAX < delimiter || delimiter < 0))
{
errno = EINVAL;
return EOF;
}
if (feof(stream) || ferror(stream))
{
return EOF;
}
if (0 == *lineptr)
{
if (0 == *n)
{
*n = NM_LINE_MAX;
}
*lineptr = malloc(*n);
if (0 == *lineptr)
{
return EOF;
}
}
p = *lineptr;
len = 0;
while (EOF != (c = fgetc(stream)))
{
if (SSIZE_MAX == (ssize_t) len)
{
errno = EOVERFLOW;
return EOF;
}
if ((size_t) len == (*n - 1))
{
*n <<= 1;
p1 = realloc(*lineptr, *n);
if (0 == p1)
{
return EOF;
}
*lineptr = p1;
p = p1 + len;
}
*p++ = (char) c;
len++;
if (c == delimiter)
{
break;
}
}
if (ferror(stream))
{
return EOF;
}
*p = 0;
return len;
}
int
main(void)
{
FILE *fp;
char *line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("/some-file", "r");
if (fp == NULL)
exit(1);
while ((read = getline(&line, &len, fp)) != -1) {
printf("Retrieved line of length %zu :\n", read);
printf("%s", line);
}
if (ferror(fp)) {
/* handle error */
}
free(line);
fclose(fp);
return 0;
}
You make the mistake of returning a pointer to an automatic variable.
The variable line is allocated in the stack and only lives as long as the function lives.
You are not allowed to return a pointer to it, because as soon as it returns the memory will be given elsewhere.
const char* func x(){
char line[100];
return (const char*) line; //illegal
}
To avoid this, you either return a pointer to memory which resides on the heap eg. lineBuffer
and it should be the user's responsibility to call free() when he is done with it.
Alternatively you can ask the user to pass you as an argument a memory address on which to write the line contents at.
I want a code from ground 0 so i did this to read the content of dictionary's word line by line.
char temp_str[20]; // you can change the buffer size according to your requirements And A single line's length in a File.
Note I've initialized the buffer With Null character each time I read line.This function can be Automated But Since I need A proof of Concept and want to design a programme Byte By Byte
#include<stdio.h>
int main()
{
int i;
char temp_ch;
FILE *fp=fopen("data.txt","r");
while(temp_ch!=EOF)
{
i=0;
char temp_str[20]={'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'};
while(temp_ch!='\n')
{
temp_ch=fgetc(fp);
temp_str[i]=temp_ch;
i++;
}
if(temp_ch=='\n')
{
temp_ch=fgetc(fp);
temp_str[i]=temp_ch;
}
printf("%s",temp_str);
}
return 0;
}

Resources