C read file line by line - c
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;
}
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; }
How to indicate the last line of the file
I want to read the txt line by line and store it to the array; I am like success to store line by line in array; I use printf("%s", loadtext[i]) with i= 0,1,2,3-20 respectively to check that things in stored in array; but I realize that the for loop had done 1912 times when I type printf("%d", i); right behind the for loops, Suppose my txt is store like this: I am a jerk I am a noob I am an idiot I am done I have another program to add new lines to the text file while this program is running. How can I detect I am done or the new line added later is the last line to not allow the for loop do so many times? Here is my code #include <stdio.h> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <string.h> int main(){ FILE *fp = fopen("abc.txt","r"); int i = 0,j=0,k=0; char ch[10000]; char loadtext[100][100]; for (i=0; ch[i] != EOF; i++){ ch[i] = fgetc(fp); if (ch[i] != '\n'){ loadtext[j][k] = ch[i]; k++; } if(ch[i] == '\n'){ loadtext[j][k] = ch[i]; k=0; j++; } } printf("%s", loadtext[0]); printf("%s", loadtext[1]); printf("%s", loadtext[2]); fclose(fp); return 0; }
To read a whole file into an "array" of pointers to char which represent the lines, you can do: #include <stddef.h> // size_t #include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE #include <stdio.h> // malloc(), realloc(), free(), fgets() #include <string.h> // strlen(), strcpy() enum { BUFFER_SIZE = 30 }; // whatever line length you suspect the input file to be + 1 int main(void) { char const *filename = "test.txt"; FILE *is = fopen(filename, "r"); if (!is) { fprintf(stderr, "Couldn't open \"%s\" for reading :(\n\n", filename); return EXIT_FAILURE; } int result = EXIT_SUCCESS; // assume a happy ending char buffer[BUFFER_SIZE]; size_t num_lines = 0; char **lines = NULL; while (fgets(buffer, sizeof(buffer), is)) { ++num_lines; char **temp = realloc(lines, num_lines * sizeof(*lines)); if (!temp) { fputs("Not enough memory :(\n\n", stderr); fclose(is); result = EXIT_FAILURE; goto cleanup; } lines = temp; size_t length = strlen(buffer); length = strlen(buffer); // remove a trailing newline if any: if (length && buffer[length - 1] == '\n') buffer[--length] = '\0'; size_t line_length = length; lines[num_lines - 1] = malloc((length + 1) * sizeof(*lines)); if (!lines[num_lines - 1]) { fputs("Not enough memory :(\n\n", stderr); fclose(is); result = EXIT_FAILURE; goto cleanup; } strcpy(lines[num_lines - 1], buffer); // as long as the buffer has been filled completely by the previous // call to fgets() and a next call to fgets() also succeeds: while (length == BUFFER_SIZE - 1 && fgets(buffer, sizeof(buffer), is)) { length = strlen(buffer); // remove a trailing newline if any: if (length && buffer[length - 1] == '\n') buffer[--length] = '\0'; char *temp = realloc(lines[num_lines - 1], line_length + length + 1); if (!temp) { fputs("Not enough memory :(\n\n", stderr); fclose(is); result = EXIT_FAILURE; goto cleanup; } lines[num_lines - 1] = temp; strcpy(lines[num_lines - 1] + line_length, buffer); line_length += length; } } fclose(is); // use lines: for (size_t i = 0; i < num_lines; ++i) puts(lines[i]); cleanup: for (size_t i = 0; i < num_lines; ++i) free(lines[i]); free(lines); return result; } Using only a fixed-size two-dimensional array and fgetc()*): #include <stdlib.h> #include <stdio.h> #include <string.h> enum { MAX_LINES = 100, MAX_LINE_LENGTH = 100 }; int main(void) { char const *filename = "test.txt"; FILE *is = fopen(filename, "r"); if (!is) { fprintf(stderr, "Couldn't open \"%s\" for reading :(\n\n", filename); return EXIT_FAILURE; } char text[MAX_LINES][MAX_LINE_LENGTH + 1] = { 0 }; // zero-initialize the array // so we don't have to care size_t num_lines = 0; // about zero terminating size_t current_column = 0; // every line int ch; // as long as we are still inside the bounds of the fixed size array // and fgetc() doesn't return EOF while (num_lines < MAX_LINES && current_column < MAX_LINE_LENGTH && (ch = fgetc(is)) != EOF) { if (ch == '\n') { // "move" num_lines and current_column to the next ++num_lines; // line. current_column = 0; continue; } text[num_lines][current_column++] = ch; } if (ch != EOF) { fputs("The file is too big :(\n\n", stderr); return EXIT_FAILURE; } for (size_t i = 0; i <= num_lines; ++i) puts(text[i]); } *) Could be done with fgets() too.
to read the txt line by line and store it to the array Code has various problems: ch[i] != EOF accesses ch[i] before it is assigned! Undefined Behavior (UB). char can be signed or unsigned. EOF is some negative. When char is unsigned the below is an infinite loop. When char is signed, ch[i] != EOF could exit the loop early. printf("%s", loadtext[0]); attempts to print loadtext[0] as if it was a string. But lacking a certain null character, and thus not a string, this leading to more UB. Lack of buffer index checks: loadtext[j][k] = ch[i]; k++; may increment k to beyond 100. Similar weak code with i. Code may fail to open the file and no check provided. Instead save the result from fgetc() as an int, test for for EOF, test for '\n' and append a null character to form strings. Some ideas for alternate code: #define LINES_N 100 #define LINE_SIZE 100 int main(void) { FILE *fp = fopen("abc.txt", "r"); if (fp) { // char ch[10000]; char loadtext[LINES_N][LINE_SIZE]; int ch_index = 0; int line_count = 0; int character; int previous_character = '\n'; while ((character = fgetc(fp)) != EOF) { // Starting a new line? if (previous_character == '\n') { if (++line_count > LINES_N) { printf("Too many lines\n"); return EXIT_FAILURE; } } loadtext[line_count - 1][ch_index++] = (char) character; loadtext[line_count - 1][ch_index] = '\0'; if (ch_index + 1 >= LINE_SIZE) { printf("Too long a line\n"); return EXIT_FAILURE; } previous_character = character; } if (line_count >= 1) printf("%s", loadtext[0]); if (line_count >= 2) printf("%s", loadtext[1]); if (line_count >= 3) printf("%s", loadtext[2]); fclose(fp); } return 0; }
What is wrong with my dynamically allocated file line reader
Constraints I have on my function is that it reads from a stream, file or standard input, and that it reads up to a newline and finished when EOF is detected. char* getLine(FILE* stream) { int capacity = LINE_MAX; char* buffer = malloc(capacity); int len = 0; char ch; while ((ch = fgetc(stream)) != '\n' && ch != EOF) { if (ch == EOF) return NULL; if (len >= capacity) { capacity *= 2; buffer = realloc(buffer, len * sizeof(char)); } buffer[len++] = ch; } buffer[len] = '\0'; if (buffer == NULL) return NULL; return buffer; } I cannot expect to have a specific length for my input. My main problem is, when using this in main; int main() { FILE* stream = stdin; // stdin now while (true) { char cmd[COMMAND_MAX]; char* arg; char* rest; char* line; printf("command $: "); line = getLine(stream); if (line == NULL) { exit(EXIT_SUCCESS); } arg = malloc(REMAINING_MAX * sizeof(char)); rest = malloc(REMAINING_MAX * sizeof(char)); int arguments = sscanf(line, "%s %s %[^\n]s", cmd, arg, rest); free(arg); printf("\n"); printf("%s, %s, %s", cmd, arg, rest); free(rest); free(line); return 0; } When I hit enter, on the actual program, I would receive duplicated input, almost as if it hasn't entered in the data. It just is stuck in memory. If I had done this with a scanf, it works perfectly but the issue is I cannot dynamically allocate memory for it as I found out earlier.
Generating array of word pointers in c
I have a problem where I have to read a text file made of 264064 words into a buffer and then create an array of word-pointers in a separate array. I am not sure how to go about creating the array of word-pointers which points to different amount of characters in the buffer. Any hints on how to approach this problem? #include <stdlib.h> #include <string.h> int main() { int i,wordCount=0; long bufsize; char ch; //Open File and get number of lines in file FILE *fp = fopen("words2.txt", "r"); if (fp == NULL) { printf("Error!"); exit(1); } do { ch = fgetc(fp); if (ch == '\n') { wordCount++; } } while (ch != EOF); fclose(fp); printf("%d\n",wordCount); //Reading Words into buffer rawtext char *rawtext; fp = fopen("words2.txt", "rb"); if (fp != NULL) { if (fseek(fp, 0L, SEEK_END) == 0) { bufsize = ftell(fp); if (bufsize == -1) { exit(1); } rawtext = malloc(sizeof(char) * (bufsize + 1)); if (fseek(fp, 0L, SEEK_SET) != 0) { exit(1); } size_t newLen = fread(rawtext, sizeof(char), bufsize, fp); if (ferror(fp) != 0) { fputs("Error reading file", stderr); } else { rawtext[newLen++] = '\0'; } } //Print out buffer printf("%s",rawtext); fclose(fp); free(rawtext);//Free allocated memory char *ptr[wordCount];//Array for word-pointers } }
If you keep your rawtext (i.e. do not free it), you could use strchr('\n') to go through the content, store to the array the current position, detect every new line char, terminate the string at this new line character, and go ahead. Thereby, your ptr-array will point to each word inside rawtext at the end (that's why you should not free rawtext then, because the pointers would then point to invalid memory): The following code should work: char* currWord = rawtext; int nrOfWords = 0; char* newlinePos; while ((newlinePos = strchr(currWord,'\n')) != NULL) { *newlinePos = '\0'; ptr[nrOfWords++] = currWord; currWord = newlinePos + 1; } if (*currWord) { ptr[nrOfWords++] = currWord; } Side note: expression char *ptr[wordCount] might put your pointer array on the stack, which has limited space, at least less than the heap. This could get a problem if your file contains a lot of words. Use char *ptr = malloc((wordCount+1) * sizeof(char*)) to reserve memory on the heap. Note also the +1 after wordCount for the case that the last word is not terminated by a new line.
Read input from popen() into char * in C
I have a FILE pointer that contains input from popen(). I want to put all of the input into a char *str, but I don't know how to do this (new to C-programming). void save_cmd(int fd) { char buf[100]; char *str; FILE *ls; if (NULL == (ls = popen("ls", "r"))) { perror("popen"); exit(EXIT_FAILURE); } while (fgets(buf, sizeof(buf), ls) != NULL) { //Don't know what to do here.... } pclose(ls); } I guess I somehow have to concatenate inside the while loop, but how is this possible when I don't know the total size in advance (I want to save the whole result in char *str). If anyone have som pointers on how to do this I would be very grateful.
so in your code you have captured a line into the buf. now you want to have it all in the *str variable correct. you need to allocate memory for it and then copy. here is an example: void save_cmd(int fd) { char buf[100]; char *str = NULL; char *temp = NULL; unsigned int size = 1; // start with size of 1 to make room for null terminator unsigned int strlength; FILE *ls; if (NULL == (ls = popen("ls", "r"))) { perror("popen"); exit(EXIT_FAILURE); } while (fgets(buf, sizeof(buf), ls) != NULL) { strlength = strlen(buf); temp = realloc(str, size + strlength); // allocate room for the buf that gets appended if (temp == NULL) { // allocation error } else { str = temp; } strcpy(str + size - 1, buf); // append buffer to str size += strlength; } pclose(ls); }