Declarando o tipo de pointers?

Acabei de ler que precisamos dar o tipo de pointers ao declará-los em C (ou C ++), ou seja:

int *point ; 

Tanto quanto sei, os pointers armazenam o endereço das variables ​​e o endereço ocupa a mesma quantidade de memory, qualquer que seja o tipo. Então, por que precisamos declarar seu tipo?

Tipo de segurança. Se você não sabe o que p deve apontar, então não haverá nada para evitar erros de categoria como

 *p = "Nonsense"; int i = *p; 

Verificação de tipo estático é uma ferramenta muito poderosa para evitar todos os tipos de erros como esse.

C e C ++ também suportam aritmética de ponteiro , que só funciona se o tamanho do tipo de destino for conhecido.

endereço ocupa a mesma quantidade de memory seja qual for o meu tipo

Isso é verdade para as plataformas populares de hoje. Mas tem havido plataformas para as quais esse não foi o caso. Por exemplo, um ponteiro para uma palavra de múltiplos bytes pode ser menor que um ponteiro para um único byte, uma vez que não precisa representar o deslocamento do byte dentro da palavra.

Porque:

  1. endereços para diferentes tipos não precisam ter o mesmo tamanho . O padrão especifica explicitamente ( norma C 2011 (rascunho online), 6.2.5 / 28).
  2. type-safety: permite que o compilador detecte quando você fornece um ponteiro incompatível a uma function ou em uma atribuição. Isso, por sua vez, evita situações feias onde você atrapalha a ordem dos argumentos para uma function.
  3. o compilador precisa saber o tipo quando o ponteiro é desreferenciado.
  4. fazer ponteiro aritmético o tamanho do object apontado para precisa ser conhecido e assim seu tipo.

Os dois últimos pontos não se aplicam a pointers void , e é por isso que eles não podem ser dereferenciados e nenhuma aritmética de ponteiro pode ser feita neles. O padrão especifica que um ponteiro void deve ser grande o suficiente para conter qualquer tipo de ponteiro (exceto pointers de function, que são uma história completamente diferente) e que a designação para e de pointers void pode ser feita sem moldes (pelo menos em C, em C ++). castings são sempre necessários) .

Um dos motivos está na aritmética dos pointers. Você não pode fazer p+1 menos que você saiba o tamanho do elemento para o qual p aponta – que é o tamanho do tipo para o qual p é um ponteiro. Se você tentasse p+1 em um void *p você provavelmente receberia uma resposta ruim (é o mesmo que se fosse feito em um char * mas talvez você não quisesse isso; um aviso e por -pedantic-errors como um erro).

Outro motivo é o tipo de segurança. Se uma function recebe como argumento um int * você não pode passar um ponteiro para char (uma string) lá. Você receberia um aviso (um erro com -Werror / -pedantic-errors ). Considere este código (fictício):

 void test(int *x) { } int main() { char *x = "xyz"; test(x); return 0; } 

A compilation (usando o gcc (GCC) 4.8.2 20131017 (Red Hat 4.8.2-1) ) fornece:

 1.c: In function 'main': 1.c:8:2: warning: passing argument 1 of 'test' from incompatible pointer type [enabled by default] test(x); ^ 1.c:1:6: note: expected 'int *' but argument is of type 'char *' void test(int *x) ^ 

Então, por que precisamos declarar seu tipo?

Você quer saber o tipo do ponteiro para fazer a verificação de tipo estático .

Também precisamos conhecer o tipo para que a aritmética de pointers funcione, por exemplo, quando indexamos em uma matriz ( que é equivalente à aritmética de pointers ) de diferentes tamanhos, o ponteiro será ajustado por uma quantidade dependente do tipo. Se olharmos para o rascunho da seção padrão C99 6.5.6 Operadores aditivos dizem ( ênfase minha ):

Para adição, ambos os operandos devem ter tipo aritmético, ou um operando deve ser um ponteiro para um tipo de object […]

Portanto, o ponteiro precisa ser um tipo de object , o que significa não estar incompleto ou vazio.

Você também disse:

o endereço ocupa a mesma quantidade de memory, qualquer que seja o tipo. Então, por que precisamos declarar seu tipo?

Isso nem sempre é verdade em C ++ o tamanho dos pointers para funções de membro pode mudar dependendo do tipo de class, um dos bons artigos que abrange isso é pointers para funções de membro são animais muito estranhos .

Além disso, podemos ver que tanto a seção de seção padrão do draft C99 6.2.5 Types, parágrafo 27, que diz:

[…] Ponteiros para outros tipos não precisam ter a mesma representação ou requisitos de alinhamento.

e o rascunho da seção padrão C ++ 3.9.2 Tipos de compostos, parágrafo 3, diz:

[…] A representação de valor dos tipos de ponteiro é definida pela implementação. Os pointers para as versões qualificadas para cv e não-csp-não-qualificadas (3.9.3) dos tipos compatíveis com layout devem ter os mesmos requisitos de representação e alinhamento de valores (3.11). […]

Não exija que os pointers tenham a mesma representação, exceto em casos específicos.

Você precisa especificar o tipo como o padrão exige. Além disso, para que não haja problemas quando você tenta executar aritmética de ponteiro como adição ou subtração.

Embora os processadores geralmente tenham instruções diferentes para “carregar um byte de um endereço”, “carregar uma meia palavra de 16 bits de um endereço” e “carregar uma palavra de 32 bits de um endereço” e, da mesma forma, para operações “armazenar”, C usa a mesma syntax para carregar um byte de um endereço para carregar qualquer outro valor de tamanho. Dada a afirmação:

 int n = *p; 

o compilador pode gerar código que carrega um byte, meia palavra ou palavra do endereço em p e armazena em n; Se p é um * float, ele pode gerar uma sequência de código mais complicada para carregar um valor de ponto flutuante em c, truncá-lo, converter para int e armazenar o valor convertido em n. Sem saber o tipo de p, o compilador não pode saber qual operação seria apropriada.

Da mesma forma, a instrução p++ pode aumentar o endereço em p por um, dois, quatro ou algum outro número. O valor pelo qual o endereço é aumentado será sobre o tipo declarado de p. Se o compilador não souber o tipo de p, não saberá como ajustar o endereço.

É possível declarar um ponteiro sem especificar o tipo de coisa para o qual ele aponta. O tipo desse ponteiro é void* . É preciso converter um void* em um tipo real de ponteiro antes de fazer qualquer coisa útil com ele; A principal utilidade do void* está no fato de que se um ponteiro é convertido em void* , ele pode ser passado como um void* por código que não sabe nada sobre o tipo real do ponteiro. Se o ponteiro é eventualmente dado ao código que conhece o seu tipo, e esse código lança o ponteiro de volta para esse tipo, o resultado será o mesmo que o ponteiro que foi convertido em void* .

Código que terá que lidar com pointers para coisas que ele não conhece, muitas vezes pode empregar void* para tais propósitos, mas o código que sabe sobre as coisas para as quais os pointers apontam deve geralmente declarar pointers do tipo apropriado.

O tipo de ponteiro chega a ser reproduzido durante a desreferência e a aritmética de pointers. Por exemplo

 int x=10; //Lets suppose the address of x=100 int *ptr=&x; //ptr has value 100 printf("The value of x is %d", *ptr); ptr++; // ptr has value 104(if int is 4bytes) 

No exemplo acima, o tipo de ponteiro é int, então o compilador começará procurando os valores armazenados nos próximos 4 bytes (se int for 4bytes) partindo do endereço de memory 100. Assim, o tipo de ponteiro diz aos compiladores quantos bytes deve procurar durante a desreferenciação. Se o tipo de ponteiro não estivesse lá, como o compilador saberia quantos bytes devem ser observados durante a desreferência. E quando fizemos ptr ++ o tipo de ponteiro informa quanto o ptr deve ser incrementado. Aqui ptr é incrementado por 4.

 char c='a'; //Lets suppose the address of c = 200 char* ptr=&c; //ptr has value 200 ptr++; //ptr has value 201(char assumed to be 1 byte) 

O tipo de ponteiro informa que ptr é incrementado em 1 byte.

Para que possa realizar operações aritméticas e outras. Considere estes dois exemplos:

 int* p; /* let the address of the memory location p pointing to be 1000*/ p++; printf("%u",p); /* prints 1004 since it is an integer pointer*/ char *p; /* let the address of the memory location p pointing to be 1000*/ p++; printf("%u",p); /* prints 1001 since it is an char pointer*/ 

Espero que isso ajude você !

Nós realmente não precisamos (veja abaixo) para declarar o tipo, mas devemos . O ponteiro armazena informações sobre a localização dos objects, enquanto o tipo define quanto espaço ocupa na memory.

O tamanho do object armazenado na memory apontada é necessário em vários casos – criação de array, atribuição, cópia da memory e, finalmente, – criação do object usando new .

No entanto, você ainda pode definir um ponteiro void , se quiser ocultar (por qualquer motivo) o tipo:

 void* dontKnowWhatTypeIsHere; 

Um ponteiro vazio é considerado universal. Ele pode apontar para qualquer object e, quando quisermos usá-lo com um tipo, faremos reinterpret_cast .

Muita declaração acima mencionada, mas é puramente correta. Agora sua pergunta porque definimos o tipo de pointers? Primeira definição do ponteiro Um ponteiro que pode conter o endereço de outra variável. A definição acima é parcial. A definição exata é o ponteiro é uma variável que pode conter o endereço de uma variável e se nós de referência (buscar o valor), ele retornará o valor do presente nesse endereço. Se um ponteiro falhar ao retornar um valor no desreferenciamento, ele não será um ponteiro. Você pode tentar que, mesmo no compilador gcc, uma variável simples também possa conter o endereço de outra variável, mas, no caso de não referência, ela dará erro. Agora o tamanho Independentemente dos tipos de dados, o tamanho do ponteiro é sempre igual ao tamanho do inteiro nesse compilador específico. Portanto, o tamanho do ponteiro no compilador gcc é 4bytes (tamanho do inteiro) e no turboc seu tamanho é 2bytes (tamanho do inteiro). Agora a questão é por que é igual ao tamanho do inteiro. Qual será o endereço de qualquer variável pode ser int, char, float etc o endereço é sempre um número inteiro inteiro e onde o número inteiro inteiro é armazena em int. É por isso que o tamanho do ponteiro é igual ao tamanho do int porque ele também armazena o endereço que é sempre um dado inteiro puro. Então qual é a diferença entre um int e char de qualquer outro ponteiro de tipos de dados. No momento da recuperação, seu compilador irá buscar o número de bytes de acordo com seus tipos de dados. Caso contrário, você receberá um erro ou não, mas para você algum resultado imprevisível, mas não para mim. Mesma regra se aplica para incrementar e decrementar o ponteiro sempre incrementa e decrementa de acordo com os tipos de dados do ponteiro. O tamanho do ponteiro não depende do tipo de dados e, portanto, a razão de sua lista de links entrar em cena, porque se você tentar declarar a estrutura dentro da mesma variável, você receberá um erro de compilation porque seu compilador não tem o tamanho de estrutura antes de sua declaração completa, mas o ponteiro auto referencial da mesma estrutura é permitido por quê? A única resposta, porque o tamanho do ponteiro não depende do tamanho do tipo de dados. Se você tiver alguma dúvida, por favor, pergunte-me. Obrigado asif aftab