Related
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;
}
In my code I'm trying to read a file, read it's lines and get them into a String array, then print them and close the file. When I run it, it fails on a seg fault and skips the last line of the file, and I just can't find the problem...
My instinct is to blame reading the array wrongly or misbehaving with the file... Am I right?
Any help or redirects would be helpful.
Thank you!
Here is the main file:
#include "files_utils.h"
int main()
{
FILE *fp = fopen("expl", "r");
if (!fp)
return -1;
long lines_count = countlines(fp);
long flen = file_length(fp);
String *lines = calloc(lines_count, sizeof(String));
printf("file length: %ld\n", flen);
printf("file lines: %ld\n", lines_count);
getlines(lines, lines_count, fp);
printf("finished\n");
for (String *sp = lines; sp != NULL; sp++)
printf("%s", *sp);
printf("before close\n");
fclose(fp);
printf("closed\n");
return 0;
}
Here is the files_utils file:
#include <stdio.h>
#include <stdlib.h>
#define MAXLINE 10
typedef char *String;
long file_length(FILE *fp)
{
/*
find the length of the file fp points to, regardless of the current position.
*/
long original_pos = ftell(fp), i = 0;
rewind(fp);
// count chars:
for (int c = fgetc(fp); c != EOF; c = fgetc(fp))
i++;
// return the file to it's original position
fseek(fp, original_pos, SEEK_SET);
return i;
}
long countlines(FILE *fp)
{
/*
find the amount of lines in file fp points to, regardless of the current position.
*/
long original_pos = ftell(fp), i = 0;
rewind(fp);
// find newlines:
for (int c = fgetc(fp); c != EOF; c = fgetc(fp))
if (c == '\n')
i++;
// return the file to it's original position
fseek(fp, original_pos, SEEK_SET);
return i;
}
String *getlines(String lines[], long maxlines, FILE *fp)
{
for (int i = 0; i <= maxlines; i++)
{
lines[i] = calloc(MAXLINE, sizeof(char));
fgets(lines[i], MAXLINE, fp);
}
return lines;
}
And it outputs
file length: 144
file lines: 21
finished
... all the lines of the file except of the last one ...
Segmentation fault (core dumped)
The problem was fixed when I changed the printing loop to run until maxlines instead of waiting for NULL. Why is this? Why would waiting for NULL raise a seg fault?
I read some data from a file, and send it through a pipe. When I read the data from the pipe, sometimes there's extra characters inside. The extra characters are also inconsistent, but normally is an extra "R" at the end.
The data I read from the file is correct, as it is always as it should be. It's only after reading it from the pipe that I encounter problems.
Could you help me find the error? I've been staring at this for ages and I can't find it.
This is the part of my code that is giving me trouble.
Thanks for your help.
int main (int argc, char **argv) {
int nClients;
int file_name_HTML[2];
create_pipes(file_name_HTML, server_access_request);
init_free_pipes();
nClients = getHTMLFilesIntoPipe(file_name_HTML);
int clients[nClients];
for(int i=0; i < nClients; i++)
{
if((clients[i] = fork()) == 0)
{
clientFunction(file_name_HTML, server_access_request);
}
}
.....
}
int getHTMLFilesIntoPipe(int *file_name_HTML)
{
int i, n = 0;
char (*lines)[MAXCHAR] = NULL;
FILE *fp;
fp = fopen("./data/listado_html.txt", "r");
if (!fp) { /* valdiate file open for reading */
err_exit("error: file open failed.\n");
}
if (!(lines = malloc (MAXLINES * sizeof *lines))) {
err_exit("error: virtual memory exhausted 'lines'.\n");
}
while (n < MAXLINES && fgets (lines[n], MAXCHAR, fp)) /* read each line */
{
char *p = lines[n]; /* assign pointer */
for (; *p && *p != '\n'; p++) {} /* find 1st '\n' */
if (*p != '\n') /* check line read */
{
int c;
while ((c = fgetc (fp)) != '\n' && c != EOF) {} /* discard remainder of line with getchar */
}
*p = 0, n++; /* nul-termiante */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
for (int i = 0; i < n; i++)
{
write(file_name_HTML[WRITE], lines[i], strlen(lines[i]));
}
free(lines);
return n;
}
void clientFunction(int *file_name_HTML, int *server_access_request)
{
char fileName[MAXCHAR];
close(file_name_HTML[WRITE]);
//Read HTML file name
read(file_name_HTML[READ], fileName, MAXCHAR - 1);
printf("%s\n", fileName);
.......
}
Expected output:
abcd1.html
abcd2.html
abcd3.html
abcd4.html
abcd5.html
Current output:
abcd1.htmlR
abcd2.htmlR
abcd3.htmlR
abcd4.htmlR
abcd5.htmlR
It is because your string is not null(\0) terminated.
As you write to the pipe excluding null(\0) terminator.
write(file_name_HTML[WRITE], lines[i], strlen(lines[i])+1);
^--- +1 to include null character.
strlen returns the length excluding null terminator.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to program a tool in C. Part of this program is to use a text file and read it line by line, while storing all lines into an array to have it available for future use.
That's what I have so far:
int main(){
FILE *fp = fopen("file.txt", "ab+");
if (fp == NULL) {
printf("FILE ERROR");
return 1;
}
int lines = 0;
int ch = 0;
while(!feof(fp)){
ch = fgetc(fp);
if(ch == '\n'){
lines++;
}
}
printf("%d\n", lines);
if (lines>0){
int i = 0;
int numProgs = 0;
char* programs[lines];
char line[lines];
FILE *file;
file = fopen("file.txt", "r");
while(fgets(line, sizeof(line), file) != NULL){
programs[i] = strdup(line);
i++;
numProgs++;
}
for (int j= 0; j<sizeof(programs); j++){
printf("%s\n", programs[j]);
}
fclose(file);
fclose(fp);
return 0;
}
My problem is im getting this output:
6 (the number of lines in the file)
Segmentation fault
How can I read a complete line by line , without knowing how long the line is in the beginning. in PHP I can do that very easily, but how can I do that in C?
Thanks for any hint!
fix like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void){
FILE *fp = fopen("file.txt", "r");//!
if (fp == NULL) {
fprintf(stderr, "FILE ERROR\n");
return 1;
}
int lines = 0;
int ch = 0;
int len = 0;//! length of line
int max_len = 0;//! max length of line
while((ch = fgetc(fp))!=EOF){//!
++len;
if(ch == '\n'){
if(max_len < len)
max_len = len;
++lines;
len = 0;
}
}
if(len)
++lines;
fprintf(stderr, "%d lines.\n", lines);
if (lines > 0){
int numProgs = 0;
char *programs[lines];//use malloc, char **programs = malloc(lines * sizeof(*programs));
char line[max_len+1];//!
rewind(fp);//!
while(fgets(line, sizeof(line), fp))
programs[numProgs++] = strdup(line);//!
for (int j= 0; j < numProgs; j++){//!
printf("%s", programs[j]);//!
free(programs[j]);//!
}
}
fclose(fp);
return 0;
}
If you truly want to read an unknown number of characters from an unknown number of lines and store those lines in an array (or, actually, in an object created from a pointer-to-pointer-to-char), then you have a number of options. POSIX getline is a line oriented input function (like fgets) which will read a line of text from the give file each time it is called, and will allocate sufficient storage to hold the line regardless of the length. (as a bonus getline returns the actual number of characters read, eliminating a subsequent call to strlen if the length is needed)
getline eliminates the need for repeated checks on whether fgets actually read the whole line, or just a partial. Further, if your lines are more than a few characters long, the buffered read provided by getline (and fgets) is quite a bit faster than character oriented input (e.g. fgetc). Don't get me wrong, there is nothing wrong with fgetc, and if your files are small and your lines short, you are not going to notice any difference. However, if you are reading a million lines of 500,000 chars each -- you will notice a significant difference.
As for an array, since you don't know how many lines you will read, you really need a pointer-to-pointer-to-char (e.g a double-ponter, char **array) so you can allocate some reasonable number of pointers to begin with, allocate and assign the lines to individual pointer until your limit is reached, then realloc array to increase the number of pointers available, and keep on reading/storing lines.
As with any code that dynamically allocates memory, your must (1) preserve a pointer to each block of memory allocated, so (2) the memory can be freed with no longer in use. You should also validate each allocation (and reallocation) to insure the allocations succeed. When using realloc, always use a temporary pointer so you can validate that realloc succeeds before assigning the new block to the original pointer. If you don't, and realloc fails, you have lost the pointer to your original block of memory that is left untouched, not freed, and you have just created a memory leak.
Lastly, always verify your memory use with a memory error check program such as valgrind on Linux. There are a number of subtle ways to misuse a block of memory.
Putting all that together, you could do something like the following. The code will read all lines from the filename provided as the first argument (or from stdin if no filename is given):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAXA = 128 }; /* initial allocation size, MAXA must be >= 1 */
int main (int argc, char **argv) {
char *line = NULL;
char **arr = NULL;
size_t i, maxa = MAXA, n = 0, ndx = 0;
ssize_t nchr = 0;
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* allocate MAXA pointers to char -- initially & validate */
if (!(arr = calloc (maxa, sizeof *arr))) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
while ((nchr = getline (&line, &n, fp)) != -1) { /* read each line */
while (line[nchr-1] == '\n') line[--nchr] = 0; /* remove '\n' */
if (!(arr[ndx] = strdup (line))) { /* allocate, copy, add to arr */
fprintf (stderr, "error: virtual memory exhausted.\n");
break; /* leave read loop, preserving existing arr */
}
if (++ndx == maxa) { /* if allocation limit reached, realloc arr */
size_t asz = sizeof *arr;
void *tmp = realloc (arr, (maxa + MAXA) * asz);
if (!tmp) { /* validate realloc succeeded */
fprintf (stderr, "error: realloc, memory exhausted.\n");
break; /* preserving original arr */
}
arr = tmp; /* assign & zero (optional) new memory */
memset (arr + (maxa + MAXA) * asz, 0, MAXA * asz);
maxa += MAXA; /* update current allocation limit */
}
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
if (line) free (line); /* free mem allocated by getline */
for (i = 0; i < ndx; i++) /* output array */
printf (" arr[%4zu] : %s\n", i, arr[i]);
for (i = 0; i < ndx; i++) /* free allocated memory */
free (arr[i]); /* free each line */
free (arr); /* free pointers */
return 0;
}
Example Use/Output
$ ./bin/getline_realloc_arr < dat/words_554.txt
arr[ 0] : Aam
arr[ 1] : Aard-vark
arr[ 2] : Aard-wolf
arr[ 3] : Aaronic
...
arr[ 549] : Accompaniment
arr[ 550] : Accompanist
arr[ 551] : Accompany
arr[ 552] : Accompletive
arr[ 553] : Accomplice
Look things over and let me know if you have any questions.
Try Online
#include <stdio.h>
#include <stdlib.h>
char * readLine (FILE * file)
{
size_t len = 0;
int c = 0, i = 0;
long pos = ftell(file);
char * out = 0;
// read the whole line
do { c = fgetc(file); len++; }
while (c!='\0' && c!='\n' && c!=EOF);
// if the cursor didn't move return NULL
if (pos == ftell(file) && c == EOF) return 0;
// allocate required memory
out = (char*)malloc(len+1);
// rewind cursor to beginning of line
fseek (file, pos, SEEK_SET);
// copy the line
do { out[i++] = fgetc(file); }
while (c!='\0' && c!='\n' && c!=EOF);
// make sure there's \0 at the end
out[i] = '\0';
return out;
}
int main (void)
{
// FILE * file = fopen("test.txt", "r");
char * line = readLine(stdin);
while(line)
{
printf(line); // print current line
free(line); // free allocated memory
line = readLine(stdin); // recur
}
return 0;
}
Read up on malloc / realloc and friends.
A first approach for reading a single line might be something along the lines of the following (note that this is a toy program, and as such omits error-checking):
size_t line_length = 0;
char *line = NULL;
char ch;
while ((ch = fgetc(fp)) != '\n') {
line = realloc(line, line_length+1);
line[line_length++] = ch;
}
// Add null character at end of line
line = realloc(line, line_length+1);
line[line_length] = 0;
The biggest problem with this is that it's slow, and especially slow for long lines. A better approach would be to keep track of the allocated and written size, and exponentially-grow size of the array as necessary, and then trim to the actual required length at the end.
Also, it'd probably be better (and simpler) to use fgets for that approach.
For reading multiple lines, you can nest this approach.
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;
}