【问题标题】:C Pointer confusionC 指针混淆
【发布时间】:2010-09-25 16:19:13
【问题描述】:

我想在内存中存储一​​个字符串,稍后再读取:

$$->desc.constant->base.id =  (char*)malloc(200);
sprintf($$->desc.constant->base.id, "%f", $1);
printf("->%s\n", $$->desc.constant->base.id); //LINE A
printf("->%i\n", $$->desc.constant); //LINE B

//SOME OTHER CODE

//Then, later on in a function call:

printf("%i", expr->desc.constant); // LINE D
printf("%s", expr->desc.constant->base.id); // LINE C

虽然 B 行和 D 行显示相同的地址,但 C 行中的 printf 失败并出现分段错误。我错过了什么?

任何帮助将不胜感激!

【问题讨论】:

  • 你不应该从 malloc 转换返回值。此外,您应该测试它是否为 0。如果 malloc 返回 0,则发生错误。阅读stanford.edu/~blp/writings/clc/malloc-cast.html
  • 这真的是 C 吗?我从未见过美元字符在 C 中用作变量名。
  • 这可能是 Yacc 语法动作的一部分。
  • $ 在 C 标识符中使用在技术上是非法的;如果您启用某个异常,某些编译器会允许它。使用 gcc,您可以使用 -fdollars-in-identifiers 选项来做到这一点。

标签: c struct pointers segmentation-fault


【解决方案1】:
printf("->%i\n", $$->desc.constant); //LINE B

这是无效的。当您在它之前的行中显示constant 实际上是一个指针时,您不能将它视为int 类型。它们不一定具有相同的 sizeof 和对齐方式。使用用于void* 的格式。它将正确输出内存地址:

printf("->%p\n", (void*)$$->desc.constant); //LINE B

【讨论】:

  • 这并没有解决代码段错误的原因——这是主要问题。
  • 它可能因此出现段错误,因为他所做的会导致未定义的行为。
【解决方案2】:
  1. 总是检查malloc的返回值。
  2. sprintf -> snprintf
  3. "%f" -> "%.*g"

这是一个例子:

/** $ gcc print_number.c -o print_number */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>


int main(int argc, char *argv[])
{
  const char* number_format = "%.*g";
  const int ndigits = 15;
  assert(ndigits > 0);
  const int maxlen = ndigits + 8 /* -0.e+001, Infinity */ + 1 /* '\0' */;

  char *str = malloc(maxlen);
  if (str == NULL) {
    fprintf(stderr, "error: malloc\n");
    exit(1);
  }    

  double number = 12345678901234567890.123456789012345678901234567890;
  /** `number = 0/0` crashes the program */;

  printf("number: %f\t", number);

  int len_wouldbe = snprintf(str, maxlen, number_format, ndigits, number);
  assert(len_wouldbe < maxlen);

  printf("%s\n", str);
  return 0;
}

输出:

number: 12345678901234567000.000000 1.23456789012346e+19

【讨论】:

    【解决方案3】:

    也许在您拥有自freed 字符串之后的两段代码的时间之间?

    $$->desc.constant->base.id =  (char*)malloc(200);
    sprintf($$->desc.constant->base.id, "%f", $1);
    printf("->%s\n", $$->desc.constant->base.id); //LINE A
    printf("->%i\n", $$->desc.constant); //LINE B
    
    //SOME OTHER CODE
    // which happens to do
    free($$->desc.constant->base.id);
    
    printf("%i", expr->desc.constant); // LINE D
    printf("%s", expr->desc.constant->base.id); // crash
    

    【讨论】:

      【解决方案4】:

      鉴于程序正在产生分段错误,我认为问题很可能是expr-&gt;desc.constant指定(指向)的结构自分配空间以来已被重用,或者可能从未真正分配空间全部。

      代码表现出各种小罪,例如使用sprintf()而不是snprintf(),并无偿分配200个字节用于浮点数的字符串表示。 (您不太可能需要那么多空间;如果这样做,您很可能应该允许至少多出 100 位数字,因为浮点数的指数范围通常是 +/-308,而您这样做的唯一原因是'd 需要 200 个字符才能允许非常大或非常小的数字。)

      您已经证明$$-&gt;desc.constant 指向同一个地方,但您没有说明该空间是如何分配的。然后在$$-&gt;desc.constant-&gt;base.id 中分配字符串空间,而没有明确为base 分配空间。

      【讨论】:

        猜你喜欢
        • 2011-09-04
        • 2016-11-08
        • 1970-01-01
        • 2014-11-18
        • 1970-01-01
        • 1970-01-01
        • 2021-11-18
        • 1970-01-01
        相关资源
        最近更新 更多