Pointers and Heap Stored Variables

UP

(C) Theodore Norvell 1999

Question 0

What is printed by this program

#include <iostream>
#include <new>
using namespace std ;

int main() {
    int *p = new(nothrow) int ;
    if( p!=0 ) {
        *p = 99 ;
        int *q = p ;
        delete q ;
        cout << *p << endl ; }
}

  1. 99
  2. 0
  3. Unknown
  4. Unknown and the program may crash.

No.

It is possible that it prints 99. But you can not count on it.

No

Try again.

Almost

Yes

The line cout << *p dereferences a pointer p. But the variable p used to point to was destroyed by the delete statement. If you try to use a variable that has been destroyed, there is no telling what will happen. In some cases your program will crash; in others it will behave oddly; sometimes nothing strange happens at all.


Question 1

What is printed by this program

#include <iostream>
#include <new>
using namespace std ;

int main() {
    int *p = new(nothrow) int ;
    if( p!=0 ) {
        delete p ;
        *p = 99 ;
        cout << 12 << endl ; }
}

  1. 99
  2. 12
  3. Unknown and the program may crash
  4. The program will crash.

Huh

Try again

No

It is possible that it prints 12. But you can not count on it.

Yes

As in the last question, there is an attempt to use a variable that no longer exists.

No

The program may crash, but you can not count on it. More often when you assign to a variable that has been destroyed already, the assignment is made to some other variable. Bugs like that are very hard to track down.


Question 2

What is wrong with this subroutine:

Matrix *strange( Matrix input ) {
    Matrix *workMatrixP = new(nothrow) Matrix ;
    *workMatrixP = input ;
    for( int i = 0 ; i < workMatrixP->rows() ; ++i )
        for( int j = 0 ; j < workMatrixP->cols() ; ++j )
            if( i != j )   workMatrixP->set(i,j, 0.0) ;
    return workMatrixP ; }

  1. Variable "workMatrixP" is declared incorrectly.
  2. "new" should not be followed by "(nothrow)"
  3. A null pointer may be dereferenced.
  4. "strange" returns a pointer to a variable that will be destroyed when "strange" is returned from.
  5. An uninitialized pointer will be dereferenced.

No

It is declared as a pointer to a Matrix, which is right.

No

In this course we will use the nothrow option of new. It means that if space can not be found for the new variable, then a null pointer should be returned.

Yes

If space can not be found in the heap region of memory for the new variable then "new" will return a null pointer. In this case "workMatrixP" will be set to the null pointer and the next line

*workMatrixP = input ;

will dereference a null pointer. It tries to assign to a variable that was never created.

No

Although the pointer variable "workMatrixP" will be destroyed when strange is returned from. The heap variable that it points to will not be destroyed.

No

The pointer variable "workMatrixP" will be initialized with the result of the "new" expression.


Question 3

What is wrong with this code?

for( int i = 0 ; i < N ; ++i ) {
    double *p = new(nothrow) double ;
    if( p== 0 ) { return false ; }
    *p = A[i] ; A[i] = B[i] ; B[i] = *p ; }

  1. A null pointer may be referenced
  2. The is no need to use a heap variable in this case.
  3. An uninitialized pointer may be dereferenced.
  4. It contains a space leak.

No.

If p is null then whatever subroutine this code is is is returned from. The subsequent dereferences of "p" will not be reached.

Yes sort of

This is entirely true. I would just use a stack variable instead of the heap variable. But there is something else that is wrong with this code.

No

The pointer "p" is initialized to the value computed by the "new" expression.

Yes

N double variables are created on the heap, but they are never destroyed. The problem can be fixed by adding a "delete p;" statement within the "for" statement, but at its end. Better yet would be to use a stack variable rather than gratuitously using the heap.


Question 4

What is wrong with the following snippet of code? (Assume sourceP is a pointer to char variable.)

// Copy a C-style string
char *targetP ;
while( *sourceP ) {
    *targetP = *sourceP ;
    ++targetP; ++sourceP ;
}
*targetP = '\0' ;

  1. It dereferences an uninitialized pointer.
  2. The expression *sourceP is not boolean
  3. The loop condition should be "sourceP" rather than "*sourceP"
  4. "sourceP" should be incremented before "targetP"

Yes

Variable "targetP" is never initialized. It could point anywhere.

No

Assuming that "sourceP" was declared as a pointer to char, then "*source" is of type char. A char will be implicitly converted to to a boolean value as follows

So the loop terminates when the nul character is reached

No

The loop condition "*sourceP" means keep looping until variable "sourceP" points to the nul character.

No

It really doesn't matter which order they are incremented in..


Question 5

What is wrong with this subroutine?

double *weird( double a, double b ) {
    double c ;
    c = pow( a*a + b*b, 0.5 ) ;
    return &c ;
}

  1. It may dereference a null pointer
  2. The type of the return expression is wrong
  3. The parameters should be passed by reference
  4. The result will be an invalid pointer

No

There are no pointer dereferences in the subroutine.

No

The subroutine is declared to return a pointer to a double. "c" is a double, so its address, "&c" is of type pointer to double.

No

Since the parameters are small and are not changed, there is no reason to pass them by reference.

Yes

The expression "&c" computes the address of c. But "c" is a stack variable and will be destroyed when the subroutine is returned from. So the result will point to a variable that no longer exists..


Question 6

Suppose we execute the following code

int a[10], *p ;
for(int i=0 ; i<10 ; ++i) a[i] = i*i ;
p = &a[3] ;

At this point, which of the following pairs of expressions are NOT equivalent

  1. "a[1]" and "p[-2]" 
  2. "&a[0]" and "p-3"
  3. "*a" and "*(p-3)"
  4. "&a[10]" and "&p[7]" 
  5. "a" and "(p-3)"

No

Since "p" points to the fourth element of "a", "p[-2]" is the second element of "a", as is "a[1]".

No

Since "p" is the address of "a[3]", "p-3" is the address of "a[0]".

No

In most contexts an array will convert to a pointer to its first element. So "*a" means the same as "*(&a[0])". Since "p-3" is the same as "&a[0]", "*(&a[0])" is the same as "*(p-3").

No

This is tricky. It looks like both expressions represent invalid pointers. That is true in that you should not dereference this pointer. However, there is no harm in forming a pointer that points just past the end of an array. Sometimes this pointer is used in for-loops as follows

for(int *p = a; p < &a[10] ; ++p ) {...}

.

Yes

In many contexts the expression "a" will convert to "&(a[0])", but it is not the same. The first is an array and the second is a pointer to an integer. You can prove this by printing the values of "sizeof(a)" and "sizeof(p-3)". The first will be 40 (assuming 4 byte ints) the second will be 4 (assuming 4 byte pointers).


Question 7

What is the type of "pp" ?

char **pp, *p, c ;

  1. No type. This is an ill-formed declaration
  2. "pp" is a pointer to a char variable.
  3. "pp" is a pointer to a pointer to a char variable.

No

This is a legitimate declaration.

No

"pp" is a pointer but its type says that it does not point to a char variable.

Yes

"pp" can hold the address of a "pointer to char" variable such as "p".


Question 8

What values will 'c', 'p', and 'pp' have after this code is executed?

char **pp, *p, c ;
pp = & p ;
*pp = & c ;
**pp = 'z' ;

  1. "pp" holds the address of variable "p"

    "p" was not initialized (and so may hold anything)

    "c" was not initialized (and so may hold anything)

  2. "pp" holds the address of variable "p"

    "p" holds the address of variable "c"

    "c" holds the character 'z'

  3. The code is illegal and will not compile
  4. The code dereferences an uninitialized pointer.

No

Since "pp" hold the address of "p", the assignment to "*pp" initializes "p". Similarly since "*pp" (i.e. "p") points to "c" the assignment to "**pp" initializes "c".

Yes

Pointers to pointers work just like ordinary pointers. The only difference is that the variables the point to are pointers themselves.

No

It will compile.

No

The dereference of "pp" happens after "pp" is initialized. The deference of "p" takes place after "p" is initialized.


UP

This page was generated by PerlInHTML.