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

时间:2017-06-18 07:15:17

标签: c xcode pointers exc-bad-access

我在Xcode中写道。我的代码应该逐行读取文本文件到指针数组* ar []。我使用了一个简单的循环,用getc()读取每个字符到c,c到* ar [i]。如果c!='\ n'* ar [i]递增。否则,* ar [i]和i都会递增。我在每一步之后添加了'printf'以便于牵引。 问题:程序将第一行读取到* ar [0],但是一旦i递增到1,我得到EXC_BAD_ACCESS(代码= 2,地址= 0x10000000000)。 MAC的VIM给出了总线错误: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:

3 个答案:

答案 0 :(得分:3)

在此处说明错误:

char *ar[MAXLINE];

这声明了一个MAXLINE指向char的数组。这些指针仍然未初始化,它们没有指向有效位置,解除引用它们是未定义的行为。在实践中,他们可能指向一些或多或少的随机&#34;位置和您的操作系统将阻止您写入某个地址,而您的流程是不允许的。

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

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

为什么要将字符a[i]增加到?您可能希望在不存在的&#34;字符串中前进一个&#34; a[i]应该指向。您需要另一个指向 的指针,否则您的程序会忘记&#34;你的字符串开始的地方。

遵循基于原始结构的工作程序,但使用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;
}

答案 1 :(得分:3)

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

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

在fopen()的规范中,没有“读取”模式。有“r”,“r +”,但没有“读”。

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

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

答案 2 :(得分:0)

这一行:

char *ar[MAXLINE];

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

但是,这些指针永远不会指向某个内存

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

以下内容:

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

    的一种方法
    #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] = '\0';
                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