简体   繁体   中英

C code about pointers

I've got this simple code that plays with pointers taken from Jon Eriksen's book that I'm trying to compile but gcc gives me warnings in compilation and segmentation fault (core dumped) when I run it.

#include<stdio.h>

int main(){
    int i;
    int int_array[5] = {1, 2, 3, 4, 5};
    char char_array[5] = {'a', 'b', 'c', 'd', 'e'};
    unsigned int hacky_nonpointer;

    hacky_nonpointer = (unsigned int)  int_array;   

    for(i=0; i < 5; i++){
        printf("[hacky_nonpointer] points to %p which contains the integer %d\n", hacky_nonpointer, *((int *) hacky_nonpointer));
        hacky_nonpointer = hacky_nonpointer + sizeof(int); // hacky_nonpointer = (unsigned int) ((int *) hacky_nonpointer + 1);
    }

    printf("\n\n\n");

    hacky_nonpointer = (unsigned int) char_array;

    for(i=0; i < 5; i++){
        printf("[hacky non_pointer] points to %p which contains the char %c\n", hacky_nonpointer, *((char *) hacky_nonpointer));
        hacky_nonpointer = hacky_nonpointer + sizeof(char); // hacky_nonpointer = (unsigned int *) ((char *) hacky_nonpointer + 1);

     }
}

Output:

command line: "gcc -g -o pointer_types5  pointer_types5.c"

pointer_types5.c: In function ‘main’:

pointer_types5.c:16:24: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     hacky_nonpointer = (unsigned int)  int_array;

pointer_types5.c:20:103: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
  points to %p which contains the integer %d\n", hacky_nonpointer, *((int *) hacky_nonpointer));

pointer_types5.c:20:47: warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘unsigned int’ [-Wformat=]
         printf("[hacky_nonpointer] points to %p which contains the integer %d\n", hacky_nonpointer, *((int *) hacky_nonpointer));

pointer_types5.c:29:24: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     hacky_nonpointer = (unsigned int) char_array;

pointer_types5.c:35:101: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
 er] points to %p which contains the char %c\n", hacky_nonpointer, *((char *) hacky_nonpointer));

pointer_types5.c:35:48: warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘unsigned int’ [-Wformat=]
         printf("[hacky non_pointer] points to %p which contains the char %c\n", hacky_nonpointer, *((char *) hacky_nonpointer));



command line: "./pointer_types5"
Segmentation fault (core dumped)

some more info about my os: 
uname -a : Linux PINGUIN 4.10.0-33-generic #37-Ubuntu SMP Fri Aug 11 10:55:28 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

This program is wrong, and the advice given in the book is obviously wrong. A pointer can be converted to a pointer, but the result is implementation-defined. A pointer-to-void can be converted to intprt_t , if such type exists, and then back again to a pointer-to-void. This is the only guarantee given by the standard. Other things might work on one platform or another, but they wouldn't be portable at all - there is no reason why you'd use them in a large program.

A %p requires a pointer-to-void as an argument. Passing an int has undefined behaviour.

The things that are attempted in the program cannot be expressed portably in C at all, but possibly a more correct program would be

#include <stdio.h>
#include <inttypes.h>

int main(void) {
    int i;
    int int_array[5] = {1, 2, 3, 4, 5};
    char char_array[5] = {'a', 'b', 'c', 'd', 'e'};
    uintptr_t hacky_nonpointer;

    hacky_nonpointer = (uintptr_t)(void *)int_array;   

    for(i=0; i < 5; i++){
        printf("[hacky_nonpointer] points to %p which contains the integer %d\n", (void *)hacky_nonpointer, *((int *)(void *)hacky_nonpointer));
        hacky_nonpointer = hacky_nonpointer + sizeof(int);
    }

    printf("\n\n\n");

    hacky_nonpointer = (uintptr_t)(void *)char_array;

    for(i=0; i < 5; i++){
        printf("[hacky non_pointer] points to %p which contains the char %c\n", (void *)hacky_nonpointer, *((char *)(void *)hacky_nonpointer));
        hacky_nonpointer = hacky_nonpointer + sizeof(char); // hacky_nonpointer = (unsigned int *) ((char *) hacky_nonpointer + 1);

     }
}

however nothing guarantees that hacky_nonpointer = hacky_nonpointer + sizeof(int); would behave as author intended on every platform. It will however work on many ordinary systems, ie Raspberry Pi, ordinary ARM architectures, modern x86-32 and x86-64 and many more.


This book doesn't teach you C, it teaches author flawed interpretation about what the C should be in his opinion.

Your OS has a 64 bit architecture and the compiler is a 32 bit - based compiler ! Due to this , there is a mismatch between the size of an integer and pointer (You can check using in-built sizeof() function ).
Instead of using an integer , try it with some other data-type (for example a 64-bit long or long long , which is again compiler dependent ) and the warning(s) will be removed !

The error messages are clear enough. The size of pointer can be greater than the size of int .

If your compiler supports C99 and the type uintptr_t in the header <stdint.h> then the program can look like

#include <stdio.h>
#include <stdint.h>

int main(void) 
{
    int i;

    int int_array[5] = {1, 2, 3, 4, 5};

    char char_array[5] = {'a', 'b', 'c', 'd', 'e'};

    uintptr_t hacky_nonpointer;


    hacky_nonpointer = ( uintptr_t )( void * )int_array;   

    for ( i=0; i < sizeof( int_array ) / sizeof( *int_array ); i++  )
    {
        printf( "[hacky_nonpointer] points to %p which contains the integer %d\n", 
            ( void * )hacky_nonpointer, *( int * ) ( void * )hacky_nonpointer );
        hacky_nonpointer = hacky_nonpointer + sizeof (int ); // hacky_nonpointer = (unsigned int) ((int *) hacky_nonpointer + 1);
    }

    printf("\n\n\n");

    hacky_nonpointer = ( uintptr_t ) ( void * )char_array;

    for ( i=0; i < sizeof( char_array ) / sizeof( *char_array ); i++ )
    {
        printf("[hacky non_pointer] points to %p which contains the char %c\n", 
            ( void * )hacky_nonpointer, *( char * )( void * ) hacky_nonpointer );
        hacky_nonpointer = hacky_nonpointer + sizeof(char); // hacky_nonpointer = (unsigned int *) ((char *) hacky_nonpointer + 1);
    }

    return 0;
}

Its output might look like

[hacky_nonpointer] points to 0x7fffffd96da0 which contains the integer 1
[hacky_nonpointer] points to 0x7fffffd96da4 which contains the integer 2
[hacky_nonpointer] points to 0x7fffffd96da8 which contains the integer 3
[hacky_nonpointer] points to 0x7fffffd96dac which contains the integer 4
[hacky_nonpointer] points to 0x7fffffd96db0 which contains the integer 5



[hacky non_pointer] points to 0x7fffffd96d90 which contains the char a
[hacky non_pointer] points to 0x7fffffd96d91 which contains the char b
[hacky non_pointer] points to 0x7fffffd96d92 which contains the char c
[hacky non_pointer] points to 0x7fffffd96d93 which contains the char d
[hacky non_pointer] points to 0x7fffffd96d94 which contains the char e

From the C Standard (7.20.1.4 Integer types capable of holding object pointers)

The following type designates an unsigned integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer:

uintptr_t

Take into account that according to the C Standard the function main without parameters shall be declared like

int main( void )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM