Question

I have text file and I want to save each line to array of strings (global defined as fileA). All I know is that all rows in file are shorter then 101 characters. I made 3 functions:

  • char * lineToString(char * filename, int line) - return value of selected line
  • int getLineCount(char * filename) - return number of lines in file (counting form 1)
  • char * fileToArray(char * filename) - return array of strings

I think this functions work as they should, problem is somewhere in main(). I had printed sizeof(...) just for debugging. Also there is many warnings in my code, how can I fix them?

Thanks!

Code:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int MAX_LINES = 1000;       //0 <= x && x < 1000
int MAX_ROW_LENGTH = 101;   //100 + 1 ('\0')
char * fileA = NULL;


char * lineToString(char * filename, int line){
    FILE * file = fopen(filename, "r");
    int currLine = 1;
    int currCol = 0;
    char currChar;
    char * string = (char *) malloc(sizeof(char)*MAX_ROW_LENGTH);
    string[0] = '\0';
    if(file != NULL && line >= 1){
        while((currChar = getc(file)) != EOF){
            if(currLine == line){
                if(currChar == '\n'){
                    string[currCol] = '\0';
                    break;
                }else{
                    string[currCol] = currChar;
                    currCol++;
                }
            }

            if(currChar == '\n') currLine++;
        }
        fclose(file);
    }
    return string;
}

int getLineCount(char * filename){
    FILE * file = fopen(filename, "r");
    int count = 0;
    char c;
    if(file != NULL){
        while((c = getc(file)) != EOF)
            if(c == '\n') count++;  
        fclose(file);
    }   
    return count;
}

char * fileToArray(char * filename){
    int i;
    int lineCount = getLineCount(filename);
    char array[lineCount][MAX_ROW_LENGTH];
    for(i = 1; i <= lineCount; i++){
        strcpy(array[i], lineToString(filename, i));
        //printf("%s\n", array[i]);
    }
    printf("%d\n",sizeof(array));
    return array;
}

int main(int argc, char **argv){

    fileA = (char *) malloc(sizeof(fileToArray(argv[1])));
    strcpy(fileA, fileToArray(argv[1]));
    printf("%d\n", (int) sizeof(fileA));
    int i;
    for(i = 0; i < (int) sizeof(fileA); i++){
        printf("%s\n", fileA[i]);
    }
    return 0;
}

Console:

matjazmav:~/FRI13_14/SE02/P2/DN/DN08$ gcc 63130148-08.c -o 63130148-08
63130148-08.c: In function ‘fileToArray’:
63130148-08.c:58:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat]
63130148-08.c:59:2: warning: return from incompatible pointer type [enabled by default]
63130148-08.c:59:2: warning: function returns address of local variable [enabled by default]
63130148-08.c: In function ‘main’:
63130148-08.c:69:3: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat]
matjazmav:~/FRI13_14/SE02/P2/DN/DN08$ ./63130148-08 input-1a input-1b
808
8
Segmentation fault (core dumped)
Was it helpful?

Solution 2

One problem I see is that you need to move the line

        if(currChar == '\n') currLine++;

inside the while loop.

I see a few more problems that I will be able to describe when I am on a full fledged computer, not a tablet.

Update

You have

char * fileToArray(char * filename){
    int i;
    int lineCount = getLineCount(filename);
    char array[lineCount][MAX_ROW_LENGTH];
    for(i = 1; i <= lineCount; i++){
        strcpy(array[i], lineToString(filename, i));
        //printf("%s\n", array[i]);
    }
    printf("%zu\n",sizeof(array));
    return array;
}

Problems with this function:

  1. The return value of char* is not compatible with the return statement return array;. array can be treated as char (*)[MAX_ROW_LENTH], but not char*.

  2. Even if the return type and return statements were made to match, the main problem is that you are trying to return a pointer to an object that will be deleted when the function returns. The pointer will be invalid in the calling function.

  3. The line

        strcpy(array[i], lineToString(filename, i));
    

    should be

        strcpy(array[i-1], lineToString(filename, i));
    

    since array indexing in C starts with 0, not 1.

Other problems:

  1. You are allocating memory for string in lineToString but you are not deallocating it.

  2. You are allocating memory for fileA in main but you are not deallocating it.

The following versions of fileToArray and main worked with my testing. I tried keep your code as much possible and modified what I thought was absolutely essential.

void fileToArray(char * filename, int lineCount, char (*array)[MAX_ROW_LENGTH])
{
    int i;
    char* string;
    for(i = 1; i <= lineCount; i++){
        string = lineToString(filename, i);
        strcpy(array[i-1], string);
        free(string);
    }
}

int main(int argc, char **argv)
{
    int i;
    int lineCount = getLineCount(argv[1]);
    char array[lineCount][MAX_ROW_LENGTH];
    fileToArray(argv[1], lineCount, array);
    for(i = 0; i < lineCount; i++){
        printf("%s\n", array[i]);
    }
    return 0;
}

PS The comments made by James R Matey in his answer are very valid. It's expensive to open and close a file just to get one line of text. I hope you find a way to incorporate his suggestions in your code.

OTHER TIPS

There are routines in the standard libraries that you should consider using.

I try to use functions in the standard libraries rather than writing my own equivalents unless absolutely necessary. The functions in the libraries are almost certainly better than anything I would write -- unless I was in the business of writing code for standard libraries.

I am a little rusty on C, my preferences today are C++ and C#. Sorry if there are some grammatical errors in the pseudo code below.

Opening and closing a file for each read of a line is very inefficient.

Here are some functions of interest

getline -- see How to explain the parameters of getline() in C -- is a workhorse for such tasks. It will automagically allocate just enough storage for a line.

rewind -- see http://www.tutorialspoint.com/c_standard_library/c_function_rewind.htm

feof -- detect end of file on a stream, see http://www.tutorialspoint.com/c_standard_library/c_function_feof.htm

Pseudo code -- not tested:

FILE fileHandle;
fileHandle = fopen(filename, "r");

if (! fileHandle) yourErrorExit();

// Count the lines -- there may be a system call that will do this more efficiently
int fileLengthInLines = 0;
char *lineBuffer = (char*)malloc(sizeOf(char) * maximumSizeOfLine]);
int bytesRead;

while (! feof(fileHandle)) {
int err;
err = getline(&lineBuffer, &bytesRead, filehandle) // ignore the string returned
if (!err) ; // process error appropriately
fileLengthInLines ++;  // this gives you your length of file in lines
}
free(lineBuffer); // we won't use it again

// allocate your array
char **stringArray;
stringArray = (char**) malloc(sizeof(char*)*fileLengthInLines);  

rewind(fileHandle); // get back to start of file

// Read lines and store
int lineNumber = 0;
char *getlineBuffer = NULL; // to force getline to allocate
int lineLength;
while (! feof(fileHandle)) {
   if (! (lineLength = getline(&getLineBuffer, 0, fileHandle))) ; // process error
   stringArray[lineNumber] = getLineBuffer;
   getLineBuffer = NULL; // to force getline to allocate on next iteration
   lineNumber++;

}

fclose(fileHandle);

// Check that all lines are processed -- compare fileLengthInLines with lineNumber
// Be sure to deallocate stringArray and its strings when you are done
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top