C Указатель путаницы - PullRequest
       18

C Указатель путаницы

3 голосов
/ 06 декабря 2008

Я хочу сохранить строку в памяти и прочитать ее позже:

$$->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 отображается один и тот же адрес, printf в строке C завершается с ошибкой сегментации. Чего мне не хватает?

Любая помощь будет принята с благодарностью!

Ответы [ 4 ]

9 голосов
/ 06 декабря 2008
printf("->%i\n", $$->desc.constant); //LINE B

Это неверно. Поскольку вы показываете строку перед ним, что constant на самом деле является указателем, вы не можете рассматривать его, как если бы он был типа int. Они не обязательно имеют одинаковый размер и выравнивание. Используйте формат, используемый для void*. Он будет правильно выводить адреса памяти:

printf("->%p\n", (void*)$$->desc.constant); //LINE B
1 голос
/ 06 декабря 2008
  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
0 голосов
/ 07 декабря 2008

Учитывая, что программа вызывает ошибку сегментации, я думаю, что проблема, скорее всего, состоит в том, что структура, обозначенная (указанная) expr->desc.constant, была повторно использована с тех пор, как было выделено пространство, или, возможно, пространство никогда не выделялось все.

Код демонстрирует различные простительные грехи, такие как использование sprintf() вместо snprintf() и безвозмездное выделение 200 байтов для строкового представления числа с плавающей запятой. (Маловероятно, что вам понадобится так много места; в противном случае вам, скорее всего, следует предоставить как минимум на 100 цифр больше, чем у вас, поскольку диапазон экспонент для чисел с плавающей запятой обычно равен +/- 308, и единственная причина нужно 200 символов, чтобы учесть невероятно большие или невероятно маленькие цифры.)

Вы показали, что $$->desc.constant указывает на то же место, но вы не показали, как распределяется это пространство. Затем вы выделяете пространство строк в $$->desc.constant->base.id, без четкого выделения пространства для base.

0 голосов
/ 06 декабря 2008

Может быть, между двумя фрагментами кода, которые у вас есть после free d строки?

$$->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
...