Search code examples
cxcodepointersexc-bad-access

C - Reading text file line by line to pointer array, getting BAD_ACCESS


I write in Xcode. My code should read a text file line by line into a pointer array *ar[]. I used a simple loop that reads each character with getc() to c, and c to *ar[i]. if c!= '\n' *ar[i] is incremented. Otherwise, both *ar[i] and i incremented. I've added 'printf' after each step for easy traction. The problem: the program reads the first line to *ar[0], but once i is incremented to 1, I get EXC_BAD_ACCESS (code=2,address=0x10000000000). MAC's VIM gives Bus error:10. Something happens in the incrementation that I can't put my finger on.

#include <stdio.h>

#define MAXLINE 10



int main()
{

    FILE *file;
    int i = 0;
    char *ar[MAXLINE];
    char c;


    file = fopen("/Users/ykeshet/Desktop/lab/alice30.txt", "read");

    while ((i < MAXLINE) && ((*ar[i]) = c = getc(file)) != EOF){
        if (c != '\n'){
            printf("%c",c);
            (*ar[i])++;
            }
        else{
            printf("%c",c);
            (*ar[i])++;
            i++;
            }
        }

    printf("\n");

}

This is the output I get (first line)

That's the variable's state in the debugger:


Solution

  • Illustrating the errors here:

    char *ar[MAXLINE];
    

    This declares an array of MAXLINE pointers to char. Those pointers remain uninitialized, they don't point to valid locations, dereferencing them is undefined behavior. In practice, they probably point to some more-or-less "random" location and your operating system will stop you writing to some address your process isn't allowed to.

    while ((i < MAXLINE) && ((*ar[i]) = c = getc(file)) != EOF){
    //                        ^ undefined behavior
    
        if (c != '\n'){
            printf("%c",c);
            (*ar[i])++;
    

    Why do you increment the character a[i] points to? You probably want to advance by one in the non-existent "string" a[i] is supposed to point to. You'd need another pointer for that, otherwise your program would "forget" where your string starts.


    Following a working program based on your original structure, but using fgets and static buffers. If you need to allocate memory dynamically or if you for some reason insist on reading character by character, this is left as an exercise.

    #include <stdio.h>
    #define MAXLINE 10
    #define LINEBUFSIZE 1024
    
    int main()
    {
        FILE *file;
        int i = 0;
        char ar[MAXLINE][LINEBUFSIZE];
    
        file = fopen("/Users/ykeshet/Desktop/lab/alice30.txt", "r");
        if (!file) return 1;
    
        while ((i < MAXLINE)
        {
             // read in next "line" by giving a pointer to the
             // first element as buffer for fgets():
             if (!fgets(&(arr[i++][0]), LINEBUFSIZE, file)) break; 
        }
        fclose(file);
        // i now holds the number of lines actually read.
    
        return 0;
    }