New Posts  All Forums:Forum Nav:

C and Null pointers

post #1 of 7
Thread Starter 
I'm currently debugging two different implementations of the same code, using gdb, code that accesses a library. One compiles directly with the source of the library, the other links to a shared object of the library. Basically, what is the difference between 0x0 and 0x1 regarding pointers?

Some context:

Program 1
Code:
typedef struct Scip SCIP;
void *A = malloc(sizeof(**(SCIP));
In gdb, the call "print (SCIP*) A *((SCIP**) (A))" gives the address "0x0".

Program 2
Code:
typedef struct Scip SCIP;
void *A = malloc(sizeof(**(SCIP));
In gdb, the call "print (SCIP*) A *((SCIP**) (A))" gives the address "0x1".

EDIT: Please ignore this code, instead refer to the code in post #5.
Edited by thealmightyone - 12/12/10 at 12:59pm
post #2 of 7
You can't access the memory at address 0. Programmers use 0 as a way of saying that the pointer is invalid and it doesn't point to anything because 0 is an invalid address.

malloc() returns a null pointer when it doesn't allocate memory and a non-zero address when the allocate is successful. This means the malloc in program 1 failed while the one in program two succeeded, assuming you printed the address stored in A right after both malloc calls.
BlackBox
(13 items)
 
  
CPUMotherboardGraphicsRAM
Q6600 3.6ghz @ 1.35V Gigabyte X38-DS4 ATI 5870 4GB Corsair Dominator 1033Mhz 
Hard DriveOSMonitorKeyboard
Hitachi P7K500 320GB 64-bit Gentoo Linux / 64-bit Vista Ultimate Sceptre X24-WG 24" WUXGA Deck 82-key 
PowerCaseMouse
Corsair 750TX BlackBox (scratch built) Logitech G5 
  hide details  
Reply
BlackBox
(13 items)
 
  
CPUMotherboardGraphicsRAM
Q6600 3.6ghz @ 1.35V Gigabyte X38-DS4 ATI 5870 4GB Corsair Dominator 1033Mhz 
Hard DriveOSMonitorKeyboard
Hitachi P7K500 320GB 64-bit Gentoo Linux / 64-bit Vista Ultimate Sceptre X24-WG 24" WUXGA Deck 82-key 
PowerCaseMouse
Corsair 750TX BlackBox (scratch built) Logitech G5 
  hide details  
Reply
post #3 of 7
Thread Starter 
Hi jpz. I've edited the original message, as the code was not quite right. I meant to print the contents of *A, not A.
post #4 of 7
Ok. What is the purpose of printing the value stored in an uninitialized space of memory? Malloc gives you an address of a piece of memory to work with, but it doesn't initialize the memory for you. The memory could contain literally anything until you initialize it.
BlackBox
(13 items)
 
  
CPUMotherboardGraphicsRAM
Q6600 3.6ghz @ 1.35V Gigabyte X38-DS4 ATI 5870 4GB Corsair Dominator 1033Mhz 
Hard DriveOSMonitorKeyboard
Hitachi P7K500 320GB 64-bit Gentoo Linux / 64-bit Vista Ultimate Sceptre X24-WG 24" WUXGA Deck 82-key 
PowerCaseMouse
Corsair 750TX BlackBox (scratch built) Logitech G5 
  hide details  
Reply
BlackBox
(13 items)
 
  
CPUMotherboardGraphicsRAM
Q6600 3.6ghz @ 1.35V Gigabyte X38-DS4 ATI 5870 4GB Corsair Dominator 1033Mhz 
Hard DriveOSMonitorKeyboard
Hitachi P7K500 320GB 64-bit Gentoo Linux / 64-bit Vista Ultimate Sceptre X24-WG 24" WUXGA Deck 82-key 
PowerCaseMouse
Corsair 750TX BlackBox (scratch built) Logitech G5 
  hide details  
Reply
post #5 of 7
Thread Starter 
The code is not mine, it's what's in the library. I'll elaborate (ignore the code in the first post to prevent confusion):

Code:
void* BMSallocMemory_call(
   size_t                size,               /**< size of memory element to allocate */
   )
{
   void* ptr;

   debugMessage("malloc %lld bytes [%s:%d]\
", (long long)size, filename, line);

   size = MAX(size, 1);
   ptr = malloc(size);

   // I'm calling my gdb print calls here, after the memory allocation.

   if( ptr == NULL )
   {
      printErrorHeader(filename, line);
   }
   return ptr;

void SCIPcreate(
   SCIP** A
   )
{
   *A = (SCIP*)BMSallocMemory_call(sizeof(**(A)))
}
This is the code in the library that I'm calling - SCIP is a structure of pointers, all to more structures. Program 1 is compiled with the source of this library, program 2 is linked to a shared object of the library.

So, on top of program 1 printing 0x0 and program 2 printing 0x1 for the value of *((SCIP**)(ptr)), after returning from BMSallocMemory_call(), if I then call "print **A", in program 1 each variable is listed as pointing to 0x0, but in program 2, each variable is listed as pointing to some seemingly random address. Ie, the output is the following:

Program 1:
Code:
(gdb) print **a
$7 = {mem = 0x0, set = 0x0, interrupt = 0x0, dialoghdlr = 0x0, totaltime = 0x0, stat = 0x0, origprob = 0x0, eventfilter = 0x0, 
  eventqueue = 0x0, branchcand = 0x0, lp = 0x0, nlp = 0x0, relaxation = 0x0, primal = 0x0, tree = 0x0, conflict = 0x0, cliquetable = 0x0, 
  transprob = 0x0, pricestore = 0x0, sepastore = 0x0, cutpool = 0x0}
Program 2:
Code:
(gdb) print **A
$3 = {mem = 0x47f3f0, set = 0x47f3f0, interrupt = 0xc6501, dialoghdlr = 0x69000865, totaltime = 0x8650027, stat = 0x266900, 
  origprob = 0x5a000283, eventfilter = 0x16e0028, eventqueue = 0x8650100, branchcand = 0x296900, lp = 0x64000265, nlp = 0x653c000c, 
  relaxation = 0x2a690008, primal = 0x46500, tree = 0x3c000c64, conflict = 0x6f000b65, cliquetable = 0x65010019, transprob = 0x865000c, 
  pricestore = 0x2a6900, sepastore = 0x69000865, cutpool = 0x2830029}
Note that program 1 is compiled using a Makefile provided by the library, whereas program 2 is compiled and linked using my own Makefile (the shared object is created using the library's Makefile). So, could there be an option in the library's Makefile that forces these variables to point to 0x0?
Edited by thealmightyone - 12/12/10 at 3:44am
post #6 of 7
A few things:

1. The code in the OP is wrong. The OP code says that you are allocating enough bytes for a pointer to a pointer to a SCIP struct(i.e. sizeof(pointer to pointer to SCIP), whereas the code you just posted is calling BMS_allocMemory_call() with sizeof(SCIP). See, A is of type SCIP** (pointer to a pointer to a SCIP struct), so **A is a SCIP struct by type, so sizeof(**A) is the same as sizeof(SCIP).

2. I believe there is a mistake in the SCIPcreate() you posted. Assuming you want to pass it the address of a pointer to a SCIP and change the pointer that was passed to the function so that it points to a new space of memory, the line should start with *A, not A. The way it is now, all you do is change the local variable A to point to a new space of memory. When control returns to where SCIPcreate() was called, the local variable A is destroyed and you just leaked the memory you allocated in SCIPcreate().

3. Here I will address print *((SCIP**)(ptr)). There are two things wrong with this. First, ptr should be a pointer to a SCIP (i.e. SCIP*). This is because you call malloc and request enough bytes for a SCIP struct. Malloc then returns the address of the first byte in the sequence of bytes it allocated for your SCIP struct. If you want to print the address of your SCIP struct, it would be print ptr. Print *((SCIP**)(ptr)) does something completely different. Casting ptr to (SCIP**) tells the compiler that the value/address stored in ptr is a pointer to a pointer to a SCIP struct. Therefore *((SCIP**)(ptr)) or *ptr reads the memory allocated by the malloc() as if it contained a pointer to a SCIP struct. But ptr actually points to a SCIP struct, so *ptr is reading the beginning of the SCIP struct you allocated as if it were a pointer to a SCIP struct. In other words, *((SCIP**)(ptr)) will printing part of the value of the first piece of data in your SCIP struct and possibly others.

The second thing wrong with printing *ptr here is that *ptr points to the memory allocated by malloc. You haven't initialized that memory yet, so it will contain random values. Printing *ptr here doesn't make any sense because the old data stored in the memory you just allocated is meaningless. I think what you want to do here is print (SCIP*) ptr to print the address of the memory malloc just gave you which will be used to store a new SCIP struct.

4. SCIPcreate() never initializes the data it allocates for your SCIP struct. Since this is not done in SCIPcreate(), you will have to do it wherever you are calling SCIPcreate(). You need to initialize each member of the structure to some meaningful value. In other words, you need to set mem, set, interrupt, etc. so they point to what you want them to point to. This may mean setting them all to null, making them point to existing structures, creating new structures for them to point to, or some combination of these things. Unless you do this, all the members in your SCIP struct will contain random values.

I am fairly certain that all the values in program 1 are 0 purely by chance.
BlackBox
(13 items)
 
  
CPUMotherboardGraphicsRAM
Q6600 3.6ghz @ 1.35V Gigabyte X38-DS4 ATI 5870 4GB Corsair Dominator 1033Mhz 
Hard DriveOSMonitorKeyboard
Hitachi P7K500 320GB 64-bit Gentoo Linux / 64-bit Vista Ultimate Sceptre X24-WG 24" WUXGA Deck 82-key 
PowerCaseMouse
Corsair 750TX BlackBox (scratch built) Logitech G5 
  hide details  
Reply
BlackBox
(13 items)
 
  
CPUMotherboardGraphicsRAM
Q6600 3.6ghz @ 1.35V Gigabyte X38-DS4 ATI 5870 4GB Corsair Dominator 1033Mhz 
Hard DriveOSMonitorKeyboard
Hitachi P7K500 320GB 64-bit Gentoo Linux / 64-bit Vista Ultimate Sceptre X24-WG 24" WUXGA Deck 82-key 
PowerCaseMouse
Corsair 750TX BlackBox (scratch built) Logitech G5 
  hide details  
Reply
post #7 of 7
Thread Starter 
Quote:
Originally Posted by jpz View Post
A few things:

1. The code in the OP is wrong. The OP code says that you are allocating enough bytes for a pointer to a pointer to a SCIP struct(i.e. sizeof(pointer to pointer to SCIP), whereas the code you just posted is calling BMS_allocMemory_call() with sizeof(SCIP). See, A is of type SCIP** (pointer to a pointer to a SCIP struct), so **A is a SCIP struct by type, so sizeof(**A) is the same as sizeof(SCIP).
The code in the OP was heavily bastardized, so it was probably wrong. Please ignore that, and just look at the code I posted in the 5th post.

Quote:
Originally Posted by jpz View Post
2. I believe there is a mistake in the SCIPcreate() you posted. Assuming you want to pass it the address of a pointer to a SCIP and change the pointer that was passed to the function so that it points to a new space of memory, the line should start with *A, not A. The way it is now, all you do is change the local variable A to point to a new space of memory. When control returns to where SCIPcreate() was called, the local variable A is destroyed and you just leaked the memory you allocated in SCIPcreate().
You are correct. The library uses quite a lot of defines regarding function calls, and it appears I incorrectly deciphered the define statements. The code has thus been revised.

Quote:
Originally Posted by jpz View Post
3. Here I will address print *((SCIP**)(ptr)). There are two things wrong with this. First, ptr should be a pointer to a SCIP (i.e. SCIP*). This is because you call malloc and request enough bytes for a SCIP struct. Malloc then returns the address of the first byte in the sequence of bytes it allocated for your SCIP struct. If you want to print the address of your SCIP struct, it would be print ptr. Print *((SCIP**)(ptr)) does something completely different. Casting ptr to (SCIP**) tells the compiler that the value/address stored in ptr is a pointer to a pointer to a SCIP struct. Therefore *((SCIP**)(ptr)) or *ptr reads the memory allocated by the malloc() as if it contained a pointer to a SCIP struct. But ptr actually points to a SCIP struct, so *ptr is reading the beginning of the SCIP struct you allocated as if it were a pointer to a SCIP struct. In other words, *((SCIP**)(ptr)) will printing part of the value of the first piece of data in your SCIP struct and possibly others.
You are very much correct. I've gone over the define statements again, and realised I misunderstood what pointer was being returned.

Quote:
Originally Posted by jpz View Post
The second thing wrong with printing *ptr here is that *ptr points to the memory allocated by malloc. You haven't initialized that memory yet, so it will contain random values. Printing *ptr here doesn't make any sense because the old data stored in the memory you just allocated is meaningless. I think what you want to do here is print (SCIP*) ptr to print the address of the memory malloc just gave you which will be used to store a new SCIP struct.

4. SCIPcreate() never initializes the data it allocates for your SCIP struct. Since this is not done in SCIPcreate(), you will have to do it wherever you are calling SCIPcreate(). You need to initialize each member of the structure to some meaningful value. In other words, you need to set mem, set, interrupt, etc. so they point to what you want them to point to. This may mean setting them all to null, making them point to existing structures, creating new structures for them to point to, or some combination of these things. Unless you do this, all the members in your SCIP struct will contain random values.

I am fairly certain that all the values in program 1 are 0 purely by chance.
I realise that calling malloc simply returns a chunk of memory containing random data, and normally needs to be initialised before using. There are further function in SCIPcreate that assigns each pointer in A a block of memory to hold the struct it points to, but as my gdb print statements are made before these, I have left these out.

So, using the revised code, I am calling "print *((SCIP*)(ptr))" directly after the malloc call, with the following gdb output:

Program 1:
Code:
289   size = MAX(size, 1);
(gdb) step
284{
(gdb) 
289   size = MAX(size, 1);
(gdb) 
290   ptr = malloc(size);
(gdb) print ptr
$1 = <value optimised out>
(gdb) step
292   if( ptr == NULL )
(gdb) print ptr
$2 = <value optimised out>
(gdb) step
290   ptr = malloc(size);
(gdb) print ptr
$3 = (void *) 0x8338448
(gdb) print *((SCIP*)(ptr))
$4 = {mem = 0x0, set = 0x0, interrupt = 0x0, dialoghdlr = 0x0, totaltime = 0x0, stat = 0x0, origprob = 0x0, eventfilter = 0x0, 
  eventqueue = 0x0, branchcand = 0x0, lp = 0x0, nlp = 0x0, relaxation = 0x0, primal = 0x0, tree = 0x0, conflict = 0x0, cliquetable = 0x0, 
  transprob = 0x0, pricestore = 0x0, sepastore = 0x0, cutpool = 0x0}
Program 2:
Code:
289   size = MAX(size, 1);
(gdb) step
290   ptr = malloc(size);
(gdb) print ptr
$1 = (void *) 0xb7fe450c
(gdb) print *((SCIP*)(ptr))
$2 = {mem = 0x1, set = 0x8232360, interrupt = 0x1, dialoghdlr = 0xb7faa6f8, totaltime = 0x0, stat = 0xb7fe45a0, origprob = 0xb7fe4480, 
  eventfilter = 0xfffffffd, eventqueue = 0x1, branchcand = 0x826e6a0, lp = 0x8229c20, nlp = 0xb7fdde80, relaxation = 0x822a0d0, 
  primal = 0xb7f77d20, tree = 0xb7fd0f20, conflict = 0xfffffffd, cliquetable = 0x1, transprob = 0x8232360, pricestore = 0x1, 
  sepastore = 0x822e0b8, cutpool = 0x0}
So, I'm noticing essentially two differences. One, the memory in program 1 has been initialised somehow. Two, program 1, I think, is optimised, as shown by "print ptr" producing output "<value optimised out>" - this is not an issue, just a possible indicator for what might be causing the memory to be initialised.

The only other explanation I can think of is that the makefile for program 1 passes some sort of optimisation option to the compiler such that malloc behaves like calloc.
Edited by thealmightyone - 12/12/10 at 3:46am
New Posts  All Forums:Forum Nav:
  Return Home
  Back to Forum: Coding and Programming