【问题标题】:Unexplainable change in C variableC 变量中无法解释的变化
【发布时间】:2013-10-16 15:13:37
【问题描述】:

我编写了一个简单的 C 程序来将 char 转换为 Tokens。一切正常,但我无法理解为什么 size 变量值会发生变化。

typedef struct _token {
    int val;
} Token;

void parse( char* code, int size, Token** tokens ) {
    int i = 0;
    for (; i < size; i++) {
        tokens[i] = malloc(sizeof(Token));
        tokens[i]->val = code[i];  
    }
}

int execute( char *path ) {
    char* code;
    if ( read_file( path, &code ) != 0 ) {
        return -1;
    }
    int size = strlen(code) - 1;
    printf("BEFORE PARSE: %d\n", size);    // 1st printf
    Token *tokens;
    parse( code, size, &tokens );        
    printf("AFTER PARSE: %d\n", size);     // 2nd printf
    return 0;
}

如果code 包含"abcde",则输出为:

BEFORE PARSE: 5
AFTER PARSE: 142786584

第二个printf 在不同的运行中显示不同的值。

请帮忙!

PS:我是C菜鸟!

编辑:

int read_file(char* path, char** code) {
    FILE* fp = fopen ( path , "rb" );
    if( !fp ) {
        return -1;
    }

    fseek( fp , 0L , SEEK_END);
    long lSize = ftell( fp );
    rewind( fp );

    /* allocate memory for entire content */
    *code = calloc( 1, lSize+1 );
    if( !*code ) {
        fclose( fp );
        return -1;
    }

    /* copy the file into the buffer */
    if( 1 != fread( *code , lSize, 1 , fp) ) {
        fclose(fp);
        return -1;
    }

    fclose( fp );
    return 0;
}

【问题讨论】:

  • 在调用 parse 之前需要 malloc 令牌。

标签: c pointers printf


【解决方案1】:

你有一个典型的缓冲区溢出案例。

char* code;

分配指向字符的指针(通常为 8 个字节),而不是用于保存文件数据的缓冲区。

相同
Token *tokens;

当您在parse 中写信给tokens 时,您会覆盖部分堆栈和size

为它们分配足够的内存!

char * code = malloc(0x1000);
Token *tokens = malloc(0x100 * sizeof(Token *));

并传递指针,而不是地址:

read_file( path, code );
parse( code, size, tokens );

这里是更正的代码:

typedef struct _token {
    int val;
} Token;

void parse( char* code, int size, Token* tokens ) {
    int i = 0;
    for (; i < size; i++) {
            // you already have memory now
        tokens[i]->val = code[i];  
    }
}

int execute( char *path ) {
    char* code =  malloc(0x1000);
    if ( read_file( path, code ) != 0 ) {
        return -1;
    }
    int size = strlen(code) - 1;
    printf("BEFORE PARSE: %d\n", size);    // 1st printf
    Token *tokens = calloc(sizeof(Token), 0x100);
    parse( code, size, tokens );        
    printf("AFTER PARSE: %d\n", size);     // 2nd printf
    return 0;
}

【讨论】:

  • 您对 Tokens 的看法是正确的,但在我看来,代码可能被更改为指向 read_file() 中分配的缓冲区——这与 execute() 中使用的实现风格一致
  • @ChrisStratton 可能是。他没有提供 read_file 的代码,所以我不能确定。不过,这将是相当不寻常的。
  • 这是 & 运算符使用的逻辑解释,并且在风格上与提供的代码一致。此外,即使您在某种程度上是正确的,这也不是导致问题的原因,问题只会在以后发生。
【解决方案2】:

这是因为令牌永远不会被初始化。将其更改为:

Tokens **tokens = malloc(sizeof(Tokens *) * size);

完成后不要忘记释放内存:

for (; i < size; i++) {
    free(tokens[i]);
}

free(tokens);

【讨论】:

  • 你确定要打电话给free(tokens[i])吗?您传递的是结构而不是指针。此外,您可能会被警告您只调用一次malloc(),但在循环中调用free()。这样他们就永远无法匹配。
  • 在分配元素类型为Token而不是Token *的数组时,sizeof (Tokens *)也是错误的。
  • @PavelŠimerda 在parse() 内,他正在分配各个令牌结构:tokens[i] = malloc(sizeof(Token)); 所以tokensToken * 的数组。但是是的,正确地说,tokens 应该声明为Token **,他还需要更新parse 访问它的方式。
  • 现在说得通了。不过,我会采取预防措施,尤其是在发布示例以使其正常工作时。如果没有不成文的初始化,我可能更喜欢calloc() 来对指针数组进行零填充。否则我会在示例中包含初始化循环。
猜你喜欢
  • 2016-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多