简单的分配如何导致分段错误?

时间:2016-10-25 15:33:34

标签: c

我正在制作一个程序将文件拆分成词条,但我不熟悉C而且我得到了一个奇怪的分段错误。运行并打印以下代码:

1
2
Segmentation Fault: 11

我已经查找了其他原因导致分段错误,并且我在2之后没有对数组做任何事情。我做错了什么?简单的分配如何导致分段错误?

#include <stdio.h>

#define CHAR_CODE 1
#define NUM_CODE 2
#define RESERVED_CHAR_CODE 3
#define SPACE_CODE 4
#define ERR_CODE 5

char token[16];
char line[128];
int lineLen = 0;
int counter = 0;
FILE *file;

void cleanToken(){
    for(int i = 0 ; i < 16; i++){
        token[i] = 0;
    }
}

void cleanLine(){
    for(int i = 0 ; i < 128; i++){
        line[i] = 0;
    }
}

void next(){
    cleanToken();
    printf("1\n");
    char c;
    if(counter == lineLen){
        printf("2\n");
        lineLen = 0;
        printf("3");
        cleanLine();
        printf("4");
        counter = 0;
        while((c=getc(file)) != 10 && c != EOF){
            if(c!=32){
                line[lineLen] = c;
                lineLen++;
            }
            printf("%d\n", lineLen);
        }
        printf("%s\n", line);
    }
    c = line[counter];
    int type = getType(c);
    while(getType(c)==type){
        token[counter] = c; 
        counter = counter + 1;
        c = line[counter];
        if(c == EOF | c == 4 | type == RESERVED_CHAR_CODE){
            break;  
        }
    }
}

int getType(int c){
    if((c > 96 & c < 123) | (c>64 & c < 91)){
        return CHAR_CODE;
    } else if(c < 58 & c > 46){
        return NUM_CODE;
    } else if(c == 32){
        return SPACE_CODE;
    } else if(c == 33 | c == 34 | (c > 36 & c < 44) | c == 45 | c == 47 | (c > 58 & c < 63)){

        return RESERVED_CHAR_CODE;  
    } else {
        return ERR_CODE;
    }
}

int main(){
    int c;
    FILE* file;
    file = fopen("test.txt", "r");
    for(int i = 0; i < 10 ;i++){
        next();
        printf("%s\n", token);
    }
    return 0;
}

3 个答案:

答案 0 :(得分:7)

您的代码中存在许多问题,其中大部分问题将在编译时使用-Wall显示,但具体而言,崩溃是由于尝试访问全局变量file引起的,尚未初始化。

您在main()中使用另一个具有相同名称的变量将其隐藏了。您初始化了那个,但不是next() 访问的全局。

此外,您的printf语句不足以进行调试,因为无法保证在程序崩溃之前将输出缓冲区刷新到控制台。如果您将\n添加到printf("3") and printf("4")行,您会看到它们在崩溃前打印出来。或者,您可以在fflush(stdout)来电后致电printf()以确保打印出来。通过执行此操作,您将看到崩溃不会因为显示的分配而发生。

gdb等调试器在调试代码时非常有用。

答案 1 :(得分:3)

编辑

DERP。刚看到eddiem的答案,他是对的 - 这是你代码中的真正问题。

但是,您仍应在循环中添加lineLen检查。

<强> ORIGINAL

打赌真钱这个问题就在这里:

while((c=getc(file)) != 10 && c != EOF){
    if(c!=32){
        line[lineLen] = c;  
        lineLen++;
    }

如果文件在一行中包含超过128个字符会怎样?你最终写完你的阵列结束,这可能会造成各种各样的混乱。

您需要添加一项检查以确保不超出数组范围:

while ( lineLen < 128 && ( c = getc( file ) ) != 10 && c != EOF ) { ... }

您没有看到34打印出来,因为您在这些printf语句中没有换行符。 stdout通常是行缓冲的,这意味着除非缓冲区已满或发送换行符,否则输出不会出现在终端上。

答案 2 :(得分:2)

您有两个不同的file变量,一个在程序顶部声明的全局变量,以及main函数中的一个全局变量。

next函数中,您使用了从未分配过的全局file

#include <stdio.h>
...
FILE *file;  // <<< global one
...


int main() {
  int c;
  FILE* file;   // <<<local one

  file = fopen("x.txt", "r");
   ...
  return 0;
}

另一个例子说明滥用全局变量导致问题的原因。

最有可能是其他问题。