2014-11-21 2 views
-1

В языке C, мы можем определить различные виды указателя, такие как:чем разница между различными видами указателя в C

  • int *p
  • char *p все они имеют одинаковый размер 4 байта или 8 байт. Все они могут использоваться в качестве параметра для printf («% s», p), так как компилятор различает их?
+0

Похожий вопрос видел вчера, довольно уверен, что есть где-то в дубликат SO. – Raptor

+0

Также есть 'int * p [10]' – mclaassen

+0

'cdecl' на межтрубках: http://cdecl.org/ – Deduplicator

ответ

2

Вы правы. Все указатели имеют одинаковый размер, и они содержат один и тот же тип данных (адрес памяти). Итак, ваш вопрос законный.

Компилятор должен знать о типе данных, на который указывает указатель, чтобы иметь возможность узнать, как с ним справиться. Например, массив в основном представляет собой указатель на (предпочтительно) выделенную область памяти. Таким образом, a[1] является сокращением на *(a+1). Но где начинается следующий элемент массива? Компилятор не знает этого, если у вашего указателя нет типа. Например, если вы скажете ему, что a указывает на int (4 байта) и, например, a = 0x100, он будет знать, что a+1 равен 0x104, потому что это адрес следующего элемента.

Кроме того, зная тип данных, на которые указывает указатель, важно знать, как разыменовать указатель (интерпретировать данные).

-2

Я думаю, что указатель просто сохранил адрес переменной. Таким образом, все указатели имеют одинаковый размер (4 байта или 8 байтов), поскольку адресная шина имеет 32 бита или 64 бит. Вы можете объявить указатели как этот

void * p = null; 
int* p2 = (int*)p; 
float* p3 = (float*)p; 

p, p2, p3 указывают на тот же адрес. Тип данных, который мы использовали при объявлении указателя, указывает компилятору, как обрабатывать данные по этому адресу.

Например, *p2 будет обрабатываться как целое число 4 байта и *p3 в качестве поплавка в 8 байтов.

2

Все дело в проверке статического типа и арифметике указателей. Возможно, это лучше всего проиллюстрировано на примере конкретного примера.

Рассмотрим это:

#include <stdio.h> 

int main(int argc, char *argv[]) 
{ 
    char x[10]; 

    char *p0  = &x[0]; /* ok */ 
    int *p1  = &x[0]; /* <- type checking, warning #1 */ 
    char (*p2)[10] = &x;  /* ok */ 
    int (*p3)[10] = &x;  /* <- type checking, warning #2 */ 

    (void)printf("sizeof(char): %ld\n", sizeof(char)); 
    (void)printf("sizeof(int): %ld\n", sizeof(int)); 

    (void)printf("p0: %p, p0+1: %p\n", (void*)p0, (void*)(p0+1)); 
    (void)printf("p1: %p, p1+1: %p\n", (void*)p1, (void*)(p1+1)); 
    (void)printf("p2: %p, p2+1: %p\n", (void*)p2, (void*)(p2+1)); 
    (void)printf("p3: %p, p3+1: %p\n", (void*)p3, (void*)(p3+1)); 

    return 0; 
} 

Важная: компилировать с -Wall (gcc -Wall -o test test.c)

Программа компилируется, но вы получите два предупреждения о несовместимых типов указателей, и это правильно.

% gcc -Wall -o test test.c 
test.c: In function ‘main’: 
test.c:9:21: warning: initialization from incompatible pointer type [enabled by default] 
    int *p1  = &x[0]; /* <- type checking, warning #1 */ 
        ^
test.c:11:21: warning: initialization from incompatible pointer type [enabled by default] 
    int (*p3)[10] = &x;  /* <- type checking, warning #2 */ 
        ^

Теперь запустите программу:

% ./test 
sizeof(char): 1 
sizeof(int): 4 
p0: 0x7fff9f6dc5c0, p0+1: 0x7fff9f6dc5c1 # + 1 char 
p1: 0x7fff9f6dc5c0, p1+1: 0x7fff9f6dc5c4 # + 1 int (4 bytes here) 
p2: 0x7fff9f6dc5c0, p2+1: 0x7fff9f6dc5ca # + 10 chars 
p3: 0x7fff9f6dc5c0, p3+1: 0x7fff9f6dc5e8 # + 10 ints (40 bytes here) 

Здесь вы можете наблюдать влияние на стрелочных арифметике: хотя все 4 указатели были инициализированы к тому же значению, одни и те же выходы операции совершенно разные результаты.

+0

. Вы можете сделать это намного лучше, удалив около 75% строк кода, который вы опубликовали. И выход одного компилятора более чем достаточно. Нет необходимости предоставлять два. –

+0

Нелегко найти баланс между широкими ответами и запутанными. Я стараюсь предоставить лучшие ответы, которые я могу, и улучшить сверхурочное отношение сигнал-шум. Я просто удалил избыточный вывод компилятора, не стесняйтесь редактировать оставшийся материал. – xbug

1

Думайте об этом как о разных в жилых помещениях.Каждая резиденция имеет 1 адрес, но резиденции разных размеров.

/* 
_________________________________________ 
/___________Studio Apartments_____________\ 
| _ _ _ _ _ _ _ _ _ _ | 
|_|0|_|1|_|2|_|3|_|4|_|5|_|6|_|7|_|8|_|9|_| 

_________________________________________ 
/____________2 Bed Apartments_____________\ 
| _  _  _  _  _  | 
|_|0|_____|1|_____|2|_____|3|_____|4|_____| 

Note: different endianness may look like: 
_________________________________________ 
/____________2 Bed Apartments_____________\ 
|  _  _  _  _  _ | 
|_____|0|_____|1|_____|2|_____|3|_____|4|_| 
*/ 

typedef studio char; //tell the compiler what a "studio" is like 
typedef apt2br short; //tell it what a 2 bedroom apartment is like 

/*Now let's build our apartments at the first available address.*/ 
studio mystudios[10] = /*the letter people live here :)*/ 
    {'A','B','E','C','I','D','O','F','U','G'}; 

/*We just told our contractor to build somewhere - record locations for later.*/ 
studio *LetterStudios=&mystudios; 

/* Let's say we want to print out all of our letter people residents 
* and no one has built an apartment complex next to them, so the data 
* following our last letter person is() a '0' 
*/ 

printf("%s\n", (char *)LetterStudios); 

/* if nothing is built we may get "ABECIDOFUG", but since we did not add our 
* own '\0' terminator then we get whatever happens to be next. This is a 
* buffer overrun ... we may get "ABECIDOFUG<lots of garbage>" or worse 
*/ 

Давайте посмотрим на случай 2 байта:

/* So let's give ourselves some boundaries and loop through it, but this 
* case has 1 byte elements, so lets look at a 2 byte array 
*/ 

apt2br myapts[5] = /*people with magic number names live here :)*/ 
    {0xFEFE, 0xB0B, 0xDADE, 0xABE, 0xBABE}; 
apt2br *MagicApartments=&myapts; 

/* to get the number of units in an apartment complex we can always divide the 
* size of the whole complex by the size of a single unit 
*/ 
for(int i=0;i<sizeof(myapts)/sizeof(myapts[0]);i++){ 
    printf("%X\n",myapts[i]); 
} 
/* Note: the sizeof() is on the array, not the pointer to it, all pointers are 
* going to be either 4 (32 bit) or 8 (64 bit), which would have printed only 
* 2 or 4 elements because the size of the "apartment" at the address is 2 
*/ 

/* you can still use the pointer though */ 
int apartments = sizeof(myapts)/sizeof(myapts[0]); 
while (apartments--) 
    printf("%X\n",*MagicApartments++); 
/* This just gives the inspector a number of apartments to inspect and points 
    * him to the first apartment to inspect. Each time he prints off the data 
    * pointed to, moves his pointer to the next apartment and decrements the number 
    * of apartments to inspect till he gets to 0. 
    * Note however that now his MagicApartments pointer is past the last apartment 
    * If he were to inspect again (without resetting MagicApartments=&myapts;) , 
    * he would end up inspecting the apartment next door... another buffer overrun 
    */ 
Смежные вопросы