reading file`s lines char by char into char** array - c

I wrote the next function that tries to read and enter each line from text file into a string array in c :
int main(int argc,char* argv[])
{
char ** lines;
readFile(argv[1],lines);
}
int readFile(char* filePath,char** lines)
{
char file_char;
int letter_in_line=0;
int line=1;
char* line_string=malloc(1024);
int j=1;
int fd=open(filePath,O_RDONLY);
if (fd < 0)
{
return 0;
}
while (read(fd,&file_char,1) >0)
{
if(file_char != '\n' && file_char != '0x0')
{
line_string[letter_in_line] = file_char;
letter_in_line++;
}
else
{
if(lines != NULL)
{
lines=(char**)realloc(lines,sizeof(char*)*line);
}
else
{
lines=(char**)malloc(sizeof(char*));
}
char* line_s_copy=strdup(line_string);
lines[line-1]=line_s_copy;
line++;
letter_in_line=0;
memset(line_string,0,strlen(line_string));
}
j++;
}
printf("cell 0 : %s",lines[0]);
return 1;
}
I have 2 questions :
1)Whenever the code reaches the print of cell 0, I'm getting
Segmentation fault (core dumped) error. What is wrong ?
2)In case I
want to see the changes in the lines array in my main, I should pass
&lines to the func and get char*** lines as an argument ? In
addition, I will need to replace every 'line' keyword with '*line' ?
*I know that I can use fopen,fget, etc... I decided to implement it in this way for a reason.

There is many issues that make your code core dump.
Here a version very similar to your code. I hope it will help you to understand this.
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
int read_file(const char *filename, char ***result)
{
/* open the file */
const int fd = open(filename, O_RDONLY);
if (fd < 0) {
*result = NULL;
return -1;
}
/* read the file characters by characters */
char *buffer = (char *)malloc(sizeof(char) * 1024);
char c;
int column = 0;
int line = 0;
*result = NULL;
/* for each characters in the file */
while (read(fd, &c, 1) > 0) {
/* check for end of line */
if (c != '\n' && c != 0 && column < 1024 - 1)
buffer[column++] = c;
else {
/* string are null terminated in C */
buffer[column] = 0;
column = 0;
/* alloc memory for this line in result */
*result = (char **)realloc(*result, sizeof(char *) *
(line + 1));
/* duplicate buffer and store it in result */
(*result)[line++] = strdup(buffer);
}
}
free(buffer);
return line;
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: %s [filename]", argv[0]);
return 1;
}
char **lines;
int line_count = read_file(argv[1], &lines);
if (line_count < 0) {
fprintf(stderr, "cannot open file %s\n", argv[1]);
return 1;
}
for(int i=0; i < line_count; i++)
printf("%s\n", lines[i]);
return 0;
}
Here an other version:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int read_file(const char *filename, char ***result)
{
/* init result */
*result = NULL;
/* open the file */
FILE *file = fopen(filename, "r");
if (file == NULL)
return -1;
/* read the file line by line */
char *buffer = (char *)malloc(sizeof(char) * 1024);
int line = 0;
while (fgets(buffer, 1024, file)) {
*result = (char **)realloc(*result, sizeof(char *) *
(line + 1));
(*result)[line++] = strdup(buffer);
}
free(buffer);
return line;
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: %s [filename]", argv[0]);
return 1;
}
char **lines;
int line_count = read_file(argv[1], &lines);
if (line_count < 0) {
fprintf(stderr, "cannot open file %s\n", argv[1]);
return 1;
}
for(int i=0; i < line_count; i++)
printf("%s\n", lines[i]);
return 0;
}

Related

Update array of strings in function

I have a working example of copy lines from a file into an array of strings. I want to move the code to copy the lines into a function to which I simply pass a pointer to the array of strings, where the lines will be stored, and a pointer to the file. However, I have tried to move the code into a function and keep getting seg faults. I have tried debugging using GDB and it seems like the problem is with the memory allocation to rows. But I can't work out what the problem is. realloc seems to be working correctly since I find the size of row increases on the 3rd iteration (using malloc_usable_size(*rows)), but then seg faults. I'm compiling with gcc -Wall -Wextra -pedantic -std=c99 -g c_programs/read_file_function.c on Linux.
Working example
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Please supply a file path:\n%s <file path>\n", argv[0]);
return EXIT_FAILURE;
}
FILE *fp = fopen(argv[1], "r");
if (!fp)
{
perror("ERROR");
return EXIT_FAILURE;
}
char **rows = (char **)malloc(sizeof(char *));
char *lineBuf = NULL;
size_t n = 0;
size_t nLines = 0;
ssize_t lineLength = 0;
size_t i = 0;
while ((lineLength = getline(&lineBuf, &n, fp)) != -1)
{
lineBuf[strcspn(lineBuf, "\n")] = 0;
lineBuf[strcspn(lineBuf, "\r")] = 0;
rows[i] = (char *)malloc(lineLength + 1);
strcpy(rows[i], lineBuf);
i++;
nLines = i;
rows = (char **)realloc(rows, (nLines + 1) * sizeof(char *));
}
printf("nLines: %lu\n", nLines);
printf("row 1: %s\n", rows[0]);
printf("row 2: %s\n", rows[1]);
printf("row 2: %s\n", rows[10]);
return 0;
}
Non working function version
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
size_t readFile(FILE **fp, char ***rows)
{
char *lineBuf = NULL;
size_t n = 0;
size_t nLines = 0;
ssize_t lineLength = 0;
size_t i = 0;
while ((lineLength = getline(&lineBuf, &n, *fp)) != -1)
{
lineBuf[strcspn(lineBuf, "\n")] = 0;
lineBuf[strcspn(lineBuf, "\r")] = 0;
*rows[i] = (char *)malloc(lineLength + 1);
strcpy(*rows[i], lineBuf);
i++;
nLines = i;
*rows = (char **)realloc(*rows, (nLines + 1) * sizeof(char *));
}
return nLines;
}
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Please supply a file path:\n%s <file path>\n", argv[0]);
return EXIT_FAILURE;
}
FILE *fp = fopen(argv[1], "r");
if (!fp)
{
perror("ERROR");
return EXIT_FAILURE;
}
char **rows = (char **)malloc(sizeof(char *));
size_t nLines = readFile(&fp, &rows);
printf("nLines: %lu", nLines);
printf("row 1: %s", rows[0]);
printf("row 2: %s", rows[1]);
return 0;
}
*rows[i] is doing *(rows[i]) - accessing ith element in the array of rows, and then dereferencing it. You want to do (*rows)[i] - dereference rows and then access ith element.
I advise to:
readFile(..., char ***rows0) {
char **rows = NULL; // temporary internal variable
...
// use rows normally
rows = stuff();
...
// when finished, assign once
*rows0 = rows;
return nLines;
}
But do not be a 3-star programmer. At best, use a structure, -> is easy to use. Like:
struct string {
char *str;
};
struct lines {
struct string *strs;
size_t cnt;
};
// #return 0 on success, otherwise error
int readFile(...., struct lines *p) {
// initialization
p->cnt = 0;
p->strs = NULL;
...
void *pnt = realloc(p->strs, (p->cnt + 1) * ....);
if (!pnt) { /* handle error */ return -1; }
p->strs = pnt;
p->strs[p->cnt]->str = malloc(lineLenght + 1);
if (!p->strs[p->cnt]->str) { /* handle error */ return -2; }
strcpy(p->strs[p->cnt]->str, lineBuf);
p->cnt++;
...
return 0; /* success */
}
int main(int argc, char **argv) {
struct lines p = {0};
if (readFile(..., &p)) {
/* handle error */
}
printf("nLines: %zu\n", p.cnt);
Do not pre-allocate memory. Initialize memory with NULL and call realloc before using memory. realloc(NULL is the same as malloc().
Check for allocation errors.

Warnings and segmentation fault core dumped

This is a program to remove particular lines in a file. It copies the lines which are needed and prints it in another file in the same directory. I'm not getting any errors except for warnings such as incompatible pointer type [-Wincompatible-pointer-types]. When I run the code I also get the prtintf statement but when entered input Segmentation fault (core dumped). Is it related to the warnings or is it something else ?
code
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
#include <ctype.h>
char *name_find(char *buf[], char *name[]) {
const char *p = NULL;
size_t len = strlen(name);
if (len > 0) {
for (p = buf ; (p = strstr(p, name)) != NULL; p++) {
if (p == buf || !isalnum((unsigned char)p[-1])) {
if (!isalnum((unsigned char)p[len]))
break; /* we have a match! */
p += len; /* next match is at least len+1 bytes away */
}
}
}
return p;
}
int main()
{
char name[25];
char buf[100];
setenv("PFILE","/home/ashwin/Desktop/FILE/",1);
char ori_path[100],new_path[100];
if (!getenv("PFILE")){
}
else{
strcpy(ori_path, getenv("PFILE"));
strcpy(new_path, getenv("PFILE"));
strcat(ori_path, "shadow");
strcat(new_path, "shadow1");
}
bool success=false;
printf("Enter the command\n ");
printf("userdel ");
FILE *fold = fopen(ori_path, "r"); // old file
FILE *fnew = fopen(new_path, "w"); // new temp file
fgets(name,25,stdin);
for(int i = 0; i < strlen(name); i++)
{
if(name[i] == '\n')
{
name[i] = '\0';
break;
}
}
while (fgets(buf, 100, fold)) {
// read lines until error or EOF
if (!name_find(buf, name)) {
fprintf(fnew, "%s", buf);
success=true;
}
}
if(success){
printf("Success !!!\n");
}
return 0;
}
char *name_find(char *buf[], char *name[])
You use char *buf[], which means buf is an array of pointers to char, not a pointer to char. Use char* buf instead. Same goes for name.
Additionally:
FILE *fold = fopen(ori_path, "r"); // old file
FILE *fnew = fopen(new_path, "w"); // new temp file
You should check if the opening of the streams to the files were successful by checking the returned pointers for a null pointer:
FILE *fold = fopen(ori_path, "r"); // old file
if(!fold)
{
fputs("Error at opening fold!", stderr);
exit(1);
}
FILE *fnew = fopen(new_path, "w"); // new temp file
if(!fnew)
{
fputs("Error at opening fnew!", stderr);
exit(1);
}
Try this code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
char *name_find(char *buf, char *name) {
const char *p = NULL;
size_t len = strlen(name);
if (len > 0) {
for (p = buf ; (p = strstr(p, name)) != NULL; p++) {
if (p == buf || !isalnum((unsigned char)p[-1])) {
if (!isalnum((unsigned char)p[len]))
break; /* we have a match! */
p += len; /* next match is at least len+1 bytes away */
}
}
}
return p;
}
int main (void)
{
char name[25];
char buf[100];
setenv("PFILE","/home/ashwin/Desktop/FILE/",1);
char ori_path[100],new_path[100];
if (!getenv("PFILE")){
}
else{
strcpy(ori_path, getenv("PFILE"));
strcpy(new_path, getenv("PFILE"));
strcat(ori_path, "shadow");
strcat(new_path, "shadow1");
}
bool success=false;
printf("Enter the command\n ");
printf("userdel ");
FILE *fold = fopen(ori_path, "r"); // old file
if(!fold)
{
fputs("Error at opening fold!", stderr);
exit(1);
}
FILE *fnew = fopen(new_path, "w"); // new temp file
if(!fnew)
{
fputs("Error at opening fnew!", stderr);
exit(1);
}
fgets(name,25,stdin);
for(unsigned int i = 0; i < strlen(name); i++)
{
if(name[i] == '\n')
{
name[i] = '\0';
break;
}
}
while (fgets(buf, 100, fold)) {
// read lines until error or EOF
if (!name_find(buf, name)) {
fprintf(fnew, "%s", buf);
success=true;
}
}
if(success){
printf("Success !!!\n");
}
return 0;
}

adding char into an array and returning

Im new to c and am trying to understand pointers.
here I am opening a file and reading the lines given. Im trying to append these lines into an array and return it from the function. I dont seem to be appending or accessing the array correctly. output[count] = status; gives an error with mismatched char and char *.
Im essentially trying to get an array with a list of words given by a file where each element in the array is a word.
char *fileRead(char *command, char output[255]) {
int count = 0;
char input[255];
char *status;
FILE *file = fopen(command, "r");
if (file == NULL) {
printf("Cannot open file\n");
} else {
do {
status = fgets(input, sizeof(input), file);
if (status != NULL) {
printf("%s", status);
strtok(status, "\n");
// add values into output array
output[count] = status;
++count;
}
} while (status);
}
fclose(file);
return output;
}
I access fileRead via:
...
char commandArray[255];
char output[255];
int y = 0;
char *filename = "scriptin.txt";
strcpy(commandArray, fileRead(filename, output));
// read from array and pass into flag function
while (commandArray[y] != NULL) {
n = flagsfunction(flags, commandArray[y], sizeof(buf), flags.position, &desc, &parentrd, right, left, lconn);
y++;
...
Example of Read from file Line by line then storing nonblank lines into an array (array of pointer to char (as char*))
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//for it does not exist because strdup is not a standard function.
char *strdup(const char *str){
char *ret = malloc(strlen(str)+1);
if(ret)
strcpy(ret, str);
return ret;
}
//Read rows up to 255 rows
int fileRead(const char *filename, char *output[255]) {
FILE *file = fopen(filename, "r");
if (file == NULL) {
perror("Cannot open file:");
return 0;
}
int count = 0;
char input[255];
while(count < 255 && fgets(input, sizeof(input), file)) {
char *line = strtok(input, "\n");
if(line)//When it is not a blank line
output[count++] = strdup(line);//Store replica
}
fclose(file);
return count;
}
int main(void){
char *output[255];//(`char *` x 255)
int number_of_read_line = fileRead("data.txt", output);
for(int i = 0; i < number_of_read_line; ++i){
printf("%s\n", output[i]);
free(output[i]);//Discard after being used
}
return 0;
}

Reading a file of strings to a string array

I'm trying to read a file (full of a word followed by a newline), to an array full of pointers to each string. Then print each word in the array, and count the number of words read. However it just prints no words and says 0 words imported.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define ARGS_REQUIRED 2
#define MAX_WORDS 50
#define MAX_WORD_LENGTH 1024
void read_file (char * argv[], char word_storage[]);
void usage (char * argv[]);
int main (int argc, char* argv[])
{
char word_storage[MAX_WORDS];
if (argc == ARGS_REQUIRED)
{
system("clear");
read_file(&argv[1], word_storage);
}
else
{
usage(&argv[0]);
}
return 0;
}
void usage (char * argv[])
{
printf("Incorrect usage, try: ./program_name %s\n", argv[1]);
}
void read_file (char * argv[], char word_storage[])
{
FILE * file_name;
char *word[MAX_WORDS][MAX_WORD_LENGTH];
int word_count = 0, i = 0, j;
if ((file_name = fopen(argv[0], "r")) == NULL)
{
printf("Cannot open file ... \n");
}
while (fscanf(file_name, "%s", *word[MAX_WORDS]) == 1)
{
for (j = 0; j < MAX_WORDS; j++)
{
if (printf("%s\n", *word[j]) == 1)
{
word_count++;
}
}
}
fclose(file_name);
printf("Imported words: %d\n", word_count);
}
You can modify your program as below. It worked for me. Please add error check for printf() function.
void read_file (char * argv[], char word_storage[])
{
FILE * file_name;
char word[MAX_WORDS][MAX_WORD_LENGTH];
int word_count = 0, i = 0, j;
if ((file_name = fopen(argv[0], "r")) == NULL)
{
printf("Cannot open file ... \n");
}
while (fscanf(file_name, "%s", word) == 1)
{
printf("%s\n",word);
word_count++;
/*
for (j = 0; j < MAX_WORDS; j++)
{
if (printf("%s\n", word[j]) == 1)
{
word_count++;
}
}
*/
}
fclose(file_name);
printf("Imported words: %d\n", word_count);
}

How to read each individual lines of a text file into their own individual variables

Hi guys I am in the second weekend of trying to find the solution to this problem. I am new at c programming and I have been trying to read each individual line of a text file and pass each of them to their own variable, where I will be able to manipulate them(such as compare them, do calculations etc).
I have a code to read each individual lines but I am unsure how to pass each line to a variable, here is the code:
#include <stdlib.h>
#include <stdio.h>
struct line_reader {
FILE *f;
char *buf;
size_t siz;
};
void
lr_init(struct line_reader *lr, FILE *f)
{
lr->f = f;
lr->buf = NULL;
lr->siz = 0;
}
char *
next_line(struct line_reader *lr, size_t *len)
{
size_t newsiz;
int c;
char *newbuf;
*len = 0;
for (;;) {
c = fgetc(lr->f);
if (ferror(lr->f))
return NULL;
if (c == EOF) {
if (*len == 0)
return NULL;
else
return lr->buf;
} else {
if (*len == lr->siz) {
newsiz = lr->siz + 4096;
newbuf = realloc(lr->buf, newsiz);
if (newbuf == NULL)
return NULL;
lr->buf = newbuf;
lr->siz = newsiz;
}
lr->buf[(*len)++] = c;
if (c == '\n')
return lr->buf;
}
}
}
void
lr_free(struct line_reader *lr)
{
free(lr->buf);
lr->buf = NULL;
lr->siz = 0;
}
int
main()
{
struct line_reader lr;
FILE *f;
size_t len;
char *line;
f = fopen("file.txt", "r");
if (f == NULL) {
perror("foobar.txt");
exit(1);
}
lr_init(&lr, f);
while (line = next_line(&lr, &len)) {
fputs("1: ", stdout);
fwrite(line, len, 1, stdout);
}
if (!feof(f)) {
perror("next_line");
exit(1);
}
lr_free(&lr);
return 0;
}
Any help would be appreciated.
What about using an array simply as a suggestion
e.g.)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char** readFile(const char *filename, size_t *lineCount){
FILE *fp;
char buff[4096];
size_t lines = 0, capacity=1024;
char **line;
if(NULL==(fp=fopen(filename, "r"))){
perror("file can't open.");
return NULL;
}
if(NULL==(line=(char**)malloc(sizeof(char*)*capacity))){
perror("can't memory allocate.");
fclose(fp);
return NULL;
}
while(NULL!=fgets(buff, sizeof(buff), fp)){
line[lines++] = strdup(buff);
if(lines == capacity){
capacity += 32;
if(NULL==(line=(char**)realloc(line, sizeof(char*)*capacity))){
perror("can't memory allocate.");
fclose(fp);
return NULL;
}
}
}
*lineCount = lines;
fclose(fp);
return (char**)realloc(line, sizeof(char*)*lines);
}
void freeMem(char** p, size_t size){
size_t i;
if(p==NULL) return;
for(i=0;i<size;++i)
free(p[i]);
free(p);
}
int main(){
size_t lines;
char **line;
if(NULL!=(line=readFile("file.txt", &lines))){//lines: set line count of file
printf("%s", line[25]);// 26th line of file, zero origin
}
freeMem(line, lines);
return 0;
}
On any POSIX-compliant system just use the m scan modifier:
for ( char *line, nl; scanf("%m[^\n]%c",&line,&nl) != EOF ; free(line) ) {
if ( !line )
strcpy(line=malloc(1),""), getchar();
// ...
}
m has been in the standard for five years now.

Resources