views:

396

answers:

4

Hi!

I want to store a string in memory and read it later:

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

Although Line B and Line D show the same address, the printf in Line C fails with a Segmentation fault. What am I missing?

Any help would really be appreciated!

+9  A: 
printf("->%i\n", $$->desc.constant); //LINE B

That is invalid. As you show the line prior to it that constant is actually a pointer, you cannot treat it as if it were of type int. They don't necassarily have the same sizeof and alignment. Use the format used for void*. It will output memory addresses properly:

printf("->%p\n", (void*)$$->desc.constant); //LINE B
Johannes Schaub - litb
This does not address why the code segfaults - which is the main question.
Jonathan Leffler
it could segfault because of that, since what he does causes undefined behavior.
Johannes Schaub - litb
A: 

Maybe between the time of the two pieces of code you have since freed the string?

$$->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
1800 INFORMATION
+1  A: 
  1. always check malloc's return value.
  2. sprintf -> snprintf
  3. "%f" -> "%.*g"

Here's an example:

/** $ 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;
}

Output:

number: 12345678901234567000.000000 1.23456789012346e+19
J.F. Sebastian
A: 

Given that the program is producing a segmentation fault, I think the problem is most likely that the structure designated (pointed to) by expr->desc.constant has been reused since the space was allocated, or possibly the space was never really allocated at all.

The code exhibits various venial sins, such as using sprintf() instead of snprintf(), and gratuitously allocating 200 bytes for the string representation of a floating point number. (You are very unlikely to need that much space; if you do, you should most probably allow for at least 100 more digits than you have, since the exponent range for floating point numbers is usually +/-308, and the only reason you'd need 200 characters is to allow for incredibly large or incredibly tiny numbers.)

You have shown that $$->desc.constant points to the same place, but you have not shown how that space is allocated. You then allocate the string space in $$->desc.constant->base.id, without clearly allocating the space for base.

Jonathan Leffler