C - 逐行读取文本文件到指针数组,得到 BAD_ACCESS

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

我写在Xcode。我的代码应该将文本文件逐行读取到指针数组 *ar[] 中。我使用了一个简单的循环,通过 getc() 将每个字符读取到 c,并将 c 读取到 *ar[i]。如果 c!= '\n' *ar[i] 递增。否则,*ar[i] 和 i 都会递增。为了便于牵引,我在每一步后添加了 'printf'。 问题: 程序将第一行读取到 *ar[0],但是一旦 i 递增到 1,我得到 EXC_BAD_ACCESS (code=2,address=0x10000000000) . MAC 的 VIM 给出总线 error:10。在增量中发生了一些我无法理解的事情。

#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:

此处说明错误:

char *ar[MAXLINE];

这声明了一个数组 MAXLINE 指向 char 的指针。这些指针保持未初始化状态,它们不指向有效位置,取消引用它们是 未定义的行为。实际上,它们可能指向某个或多或少的 "random" 位置,并且您的操作系统将阻止您写入某些您的进程不允许的地址。

while ((i < MAXLINE) && ((*ar[i]) = c = getc(file)) != EOF){
//                        ^ undefined behavior

    if (c != '\n'){
        printf("%c",c);
        (*ar[i])++;

为什么要增加 a[i] 指向的字符?您可能想在不存在的 "string" a[i] 应该指向的地方前进一个。您需要 that 的另一个指针,否则您的程序将 "forget" 字符串开始的位置。


遵循基于您的原始结构的工作程序,但使用 fgets 和静态缓冲区。如果您需要动态分配内存,或者如果您出于某种原因坚持逐个字符地读取,这将留作练习。

#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;
}

Felix Palmen 说了什么但也注意到这一行:

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

在 fopen() 的规范中没有 "read" 模式。有 "r"、"r+",但没有 "read"。

http://www.cplusplus.com/reference/cstdio/fopen/

我正在使用 GCC 5.3.0 并尝试使用 "read" 打开文件会破坏程序,因此您可能需要小心。

这一行:

char *ar[MAXLINE];

声明一个包含 10 个指向 char 的指针的数组。

但是,这些指针从未设置为指向某些内存

但这与代码将输入读入该指针数组的问题无关紧要。 它应该将输入读入指针指向的位置,但是这要求指针实际指向应用程序拥有的内存。

以下:

  1. 干净地编译
  2. 正确检查错误(但并不总是正确处理它们,因为代码应该在 any/every 退出点
  3. 处清理
  4. 记录包含每个头文件的原因
  5. 缩进代码以提高我们人类的可读性
  6. 为了便于阅读,应用适当的水平间距
  7. 为了可读性,通过单个空行分隔代码块
  8. 仅在使用变量时(或之前)声明变量。
  9. 使用源代码文件untitled1.c作为输入。
  10. 使用 #define 语句为任何 'magic' 数字赋予有意义的名称。
  11. 如果行太长或行太多或遇到 EOF,'while()' 循环将退出
  12. 使用有效的第二个参数调用 fopen()

以下代码是实现功能的一种方法::

#include <stdio.h>  // fopen(), fclose(), perror(), printf(), putc()
#include <stdlib.h> // exit(), EXIT_FAILURE, malloc(), free()


// prototypes
void cleanup(  FILE *fp, char **ar );


#define MAXLINE 100
#define MAX_LEN 100


int main( void )
{
    char **ar = calloc( MAXLINE, sizeof( char* ) );

    for( size_t i=0; i<MAXLINE; i++)
    {
        ar[i] = malloc( MAX_LEN );
        if( !ar[i] )
        { // then malloc failed
            perror( "malloc failed" );
            cleanup( NULL, ar );
            exit( EXIT_FAILURE );
        }

        // implied else, malloc successful
    }


    FILE *fp = fopen("untitled1.c", "r");
    if( !fp )
    { // then fopen failed
        perror( "fopen failed" );
        cleanup( fp, ar );
        exit( EXIT_FAILURE );
    }

    // implied else, fopen successful

    size_t col = 0;   // 'size_t' because value will never be <0
    size_t row = 0;   // "
    int c;

    while ( (row < MAXLINE)
        &&  (col < MAX_LEN )
        &&  ( (c = getc(fp)) != EOF) )
    {
        if (c != '\n')
        { // normal char read
            ar[row][col] = (char)c;
            col++;
        }

        else
        { // newline read
            // terminate the row
            ar[row][col] = '[=11=]';
            row++;     // step to next row
            col = 0;   // reset to first column of new row
        }

        // echo byte read from file to terminal
        printf("%c",c);
    }

    putc('\n', stdout);

    cleanup( fp, ar );
} // end function: main


void cleanup(  FILE *fp, char **ar )
{
    if( NULL != fp )
    {
        fclose( fp );
    }

    for( size_t i = 0; i < MAXLINE; i++ )
    {
        free( ar[i] );
    }
} // end function: cleanup