Questions about C pointers

In the code below, I made an integer array and tried to print it using the DisplayIntArray function to try and understand how pointers work.

Some questions are embedded in the comments.

/*==========================================================
 * pointer tests
 *========================================================*/

#include <stdio.h>

void DisplayIntArray(char *Name, int *Data, int lenArray) {
  /* Display integer array data */
  int m;
  printf("%s = \n", Name);
  for(m = 0; m < lenArray; m++, printf("\n")){
    printf("%d ", *(Data+m));
    printf("%d ", Data[m]);
    // how come these two print statements display the same thing?
  }
}

void DisplayDoubleArray(char *Name, double *Data, int lenArray) {
  /* Display double array data */
  int m;
  printf("%s = \n", Name);
  for(m = 0; m < lenArray; m++, printf("\n")){
    printf("%f ", *(Data+m));
    printf("%f ", Data[m]);
  }
}


int main ()
{

  int int_array[5] = {1, 2, 3, 4, 5};
  int *int_array_p = &int_array[0];

  // print array with function DisplayIntArray
  // this works fine
  DisplayIntArray("int array", int_array_p, 5);
  printf("\n");


  // Curiously the function still works when passing the actual
  // array instead of the pointer.
  DisplayIntArray("int array", int_array, 5);
  printf("\n");


  // print array using the wrong function
  // This print should fail because I'm passing an integer value pointer
  // into a double. But shouldn't it print the first element
  // correctly? - Why not?
  DisplayDoubleArray("int array", int_array_p, 5);
  printf("\n");


  return 0;
}

      

Code output:

int array = 
1 1 
2 2 
3 3 
4 4 
5 5 

int array = 
1 1 
2 2 
3 3 
4 4 
5 5 

int array = 
0.000000 0.000000 
0.000000 0.000000 
0.000000 0.000000 
-0.000000 -0.000000 
0.000000 0.000000

      

+3


source to share


5 answers


printf ("% d", * (data + m));
printf ("% d", data [m]);
// why do these two print statements display the same thing?

Because they mean the same thing; Data [m] and m [Data] will both be equivalent to * (Data + m) here, they all refer to the same item.

// Curiously, the function still works when passing an actual
// array instead of a pointer.



When you try to use an array in a type expression, it automatically decays to a pointer to an array , which means that you cannot traverse the array itself, only a pointer to it.

// print the array using the wrong function
// This print should fail because I am passing an integer pointer
// to double. But shouldn't the first element be printed
// correctly? - Why not?

This behavior is undefined, in theory anything can happen. In practice, your compiler will most likely try to interpret the original bit pattern of your int array as if it were a double array, and this matches floating point values ​​very close to 0.0.
Most likely, it won't even print the first element correctly, because int and double are stored differently in memory.

+2


source


In C, if you have a pointer p

that points to an array and an integral value i

, then is the p[i]

same as *(p+i)

. Both are evaluated using the i

th element of the array.

With this in mind, it makes sense that

printf("%d ", *(Data+m));
printf("%d ", Data[m]);

      

print the same.

You said:

// Curiously the function still works when passing the actual
// array instead of the pointer.

      

When an array variable is used in an expression such as a call DisplayIntArray

, the variable is evaluated by a pointer to the first element. Hence,



   DisplayIntArray("int array", int_array_p, 5);
   DisplayIntArray("int array", int_array, 5);

      

are equivalent.

You said:

// This print should fail because I'm passing an integer value pointer
// into a double. But shouldn't it print the first element
// correctly? - Why not?
DisplayDoubleArray("int array", int_array_p, 5);

      

Here, the type of the argument and the variable used in the argument are not the same. Using gcc I get the following warning:

soc.c: In function ‘main’:
soc.c:51:35: warning: passing argument 2 of ‘DisplayDoubleArray’ from incompatible pointer type
   DisplayDoubleArray("int array", int_array_p, 5);
                                   ^
soc.c:18:6: note: expected ‘double *’ but argument is of type ‘int *’
 void DisplayDoubleArray(char *Name, double *Data, int lenArray) {

      

On this call, the program must exhibit undefined behavior.

+2


source


printf("%d ", *(Data+m));
printf("%d ", Data[m]);

      

Why do these two print statements display the same thing?

They display the same thing because there are p

at least at least m + 1

expression elements for a pointer to an array *(p + m)

and p[m]

mean the same thing. They are 100% synonymous. You can take this as part of the definition of pointer arithmetic if you like.


int int_array[5] = {1, 2, 3, 4, 5};
int *int_array_p = &int_array[0];

      

this works great:

DisplayIntArray("int array", int_array_p, 5);

      

Curiously, the function continues to run while passing in the actual array:

DisplayIntArray("int array", int_array, 5);

      

Yes, because in most contexts the name of the array is automatically converted to a pointer to the first element of the array. This, by the way, is related to your previous question.


Shouldn't [this] print the first element correctly? - Why [is] not?

DisplayDoubleArray("int array", int_array_p, 5);

      

In DisplayDoubleArray()

you are pretending that the pointer argument points to the bytes of the representation of a double

, but it is not. Therefore, dereferencing a pointer creates undefined behavior.

Suppose the observed actual behavior is getting a value of a type double

, which is reasonably likely, but doesn't have to be, since the behavior is undefined - you then tell printf()

it that it gets a value of a type instead float

. For this reason, the behavior printf()

is undefined as well. Perhaps printf()

interprets the first sizeof(float)

bytes of the value representation (undefined) double

as if it were a value representation float

, but again, undefined. In any case, representations double

and float

are certainly different from representations int

, and they usually differ from each other. There is no reason to think that any element in the array should be printed correctly this way.

Also, the type representation is double

probably larger than the type representation int

on your system (8 bytes double

and 4 bytes int

are common). If so, then execution DisplayDoubleArray()

will try to access the end of your underlying array, unless some of the other aforementioned undefined actions allow it. Accessing the end of the array also results in undefined behavior.

+1


source


Most of this is because the name is implicitly converted to a pointer to the first element of the array .

For more information, see the comments for each block listed.

printf("%d ", *(Data+m));
printf("%d ", Data[m]);
// how come these two print statements display the same thing?

      

This is pointer arithmetic. Du to convert array names, indexing into an array is identical to adding an index to a pointer to the first element of the array (which could be the name of the array itself).

// Curiously the function still works when passing the actual
// array instead of the pointer.
DisplayIntArray("int array", int_array, 5);

      

See above.

// print array using the wrong function
// This print should fail because I'm passing an integer value pointer
// into a double. But shouldn't it print the first element   
// correctly? - Why not?  
DisplayDoubleArray("int array", int_array_p, 5);

      

It should generate a compiler warning about implicit pointer conversion. If not, turn on warnings, if nothing appears, kill your compiler, or remove the provider. Converting one pointer to another is guaranteed only to return it without losing information. Any access to the converted pointer has undefined behavior . This means something can happen . Your computer can grow teeth and bite you. Thinking about what might happen is useless, just don't!

Just FYI: binary representation int

and float

/ double

not significantly surprising.

+1


source


int *int_array_p = &int_array[0];

      

Only useful if you want to manipulate memory addresses that are not region-specific. Otherwise, you should know that arrays decay to a pointer to the first element of the array.

Hence, it &int_array[0];

will be the same as soon as int_array

. They both return the offset address of the array. You don't need to use the reference operator &

as it returns "address" and pointers are already "address"


double

is guaranteed to be no more than 8 bytes, while int is guaranteed to be max 4 bytes (on x64-bit architectures, excluding some rare cases). Casting a reference to an integer data type to a pointer to double

is undefined behavior, and modern compilers will give you a warning. However, if you ask for a value to be printed like %i

or %d

, it may return the correct result for you, otherwise it will read large regions of memory and depending on your entity, it will give you a lot of unexpected results.

0


source







All Articles