Por que usar ponteiros? [fechadas]

356

Sei que essa é uma pergunta realmente básica, mas comecei com alguma programação básica em C ++ depois de codificar alguns projetos com linguagens de alto nível.

Basicamente, tenho três perguntas:

  1. Por que usar ponteiros sobre variáveis ​​normais?
  2. Quando e onde devo usar os ponteiros?
  3. Como você usa ponteiros com matrizes?
Kevin
fonte
5
Discutido antes nesta pergunta Espero que ajude!
Doug T.
4
Para obter uma lista de livros, consulte stackoverflow.com/questions/388242/… . Depois do Java, achei o Ac ++ acelerado muito útil.
Jabba
163
Usamos ponteiros porque é mais fácil fornecer um endereço para alguém em sua casa do que dar uma cópia de sua casa para todos.
Rishi Dua
14
@RishiDua Essa é a melhor explicação de um ponteiro que eu já encontrei. Obrigado por isso, tem aumentado a minha :) compreensão
Josh
2
Ponteiros também podem ser usados ​​quando você deseja retornar mais de um valor / objeto.
Gaurav

Respostas:

172
  • Por que usar ponteiros sobre variáveis ​​normais?

A resposta curta é: não. ;-) Ponteiros devem ser usados ​​onde você não pode usar mais nada. É devido à falta de funcionalidade apropriada, à falta de tipos de dados ou ao puro desempenho. Mais abaixo ...

  • Quando e onde devo usar os ponteiros?

A resposta curta aqui é: Onde você não pode usar mais nada. Em C, você não tem suporte para tipos de dados complexos, como uma string. Também não há como passar uma variável "por referência" para uma função. É aí que você tem que usar ponteiros. Também é possível que eles apontem para praticamente qualquer coisa, listas vinculadas, membros de estruturas e assim por diante. Mas não vamos entrar nisso aqui.

  • Como você usa ponteiros com matrizes?

Com pouco esforço e muita confusão. ;-) Se falamos sobre tipos de dados simples, como int e char, há pouca diferença entre uma matriz e um ponteiro. Essas declarações são muito semelhantes (mas não são as mesmas - por exemplo, sizeofretornarão valores diferentes):

char* a = "Hello";
char a[] = "Hello";

Você pode acessar qualquer elemento da matriz como este

printf("Second char is: %c", a[1]);

Índice 1, pois a matriz começa com o elemento 0. :-)

Ou você poderia igualmente fazer isso

printf("Second char is: %c", *(a+1));

O operador ponteiro (o *) é necessário, pois estamos dizendo ao printf que queremos imprimir um caractere. Sem o *, a representação de caracteres do próprio endereço de memória seria impressa. Agora estamos usando o próprio personagem. Se tivéssemos usado% s em vez de% c, pediríamos ao printf para imprimir o conteúdo do endereço de memória apontado por 'a' mais um (neste exemplo acima) e não precisaríamos colocar o * em frente:

printf("Second char is: %s", (a+1)); /* WRONG */

Mas isso não teria apenas impresso o segundo caractere, mas todos os caracteres nos próximos endereços de memória, até que um caractere nulo (\ 0) fosse encontrado. E é aí que as coisas começam a ficar perigosas. E se você tentar imprimir acidentalmente uma variável do tipo inteiro em vez de um ponteiro de char com o formatador% s?

char* a = "Hello";
int b = 120;
printf("Second char is: %s", b);

Isso imprimiria o que fosse encontrado no endereço de memória 120 e continuaria imprimindo até que um caractere nulo fosse encontrado. É errado e ilegal executar essa instrução printf, mas provavelmente funcionaria de qualquer maneira, pois um ponteiro é realmente do tipo int em muitos ambientes. Imagine os problemas que você pode causar se usar sprintf () e atribua esse "conjunto de caracteres" por muito tempo a outra variável, que só possui um determinado espaço limitado alocado. Você provavelmente acabaria escrevendo sobre outra coisa na memória e causaria uma falha no programa (se tiver sorte).

Ah, e se você não atribuir um valor de string ao array / ponteiro de caracteres quando o declarar, DEVE alocar uma quantidade de memória suficiente antes de atribuir um valor. Usando malloc, calloc ou similar. Isso porque você declarou apenas um elemento em sua matriz / um único endereço de memória para apontar. Então, aqui estão alguns exemplos:

char* x;
/* Allocate 6 bytes of memory for me and point x to the first of them. */
x = (char*) malloc(6);
x[0] = 'H';
x[1] = 'e';
x[2] = 'l';
x[3] = 'l';
x[4] = 'o';
x[5] = '\0';
printf("String \"%s\" at address: %d\n", x, x);
/* Delete the allocation (reservation) of the memory. */
/* The char pointer x is still pointing to this address in memory though! */
free(x);
/* Same as malloc but here the allocated space is filled with null characters!*/
x = (char *) calloc(6, sizeof(x));
x[0] = 'H';
x[1] = 'e';
x[2] = 'l';
x[3] = 'l';
x[4] = 'o';
x[5] = '\0';
printf("String \"%s\" at address: %d\n", x, x);
/* And delete the allocation again... */
free(x);
/* We can set the size at declaration time as well */
char xx[6];
xx[0] = 'H';
xx[1] = 'e';
xx[2] = 'l';
xx[3] = 'l';
xx[4] = 'o';
xx[5] = '\0';
printf("String \"%s\" at address: %d\n", xx, xx);

Observe que você ainda pode usar a variável x depois de executar um free () da memória alocada, mas não sabe o que está lá. Observe também que os dois printf () podem fornecer endereços diferentes, pois não há garantia de que a segunda alocação de memória seja executada no mesmo espaço que o primeiro.

Tooony
fonte
8
Seu exemplo com 120 está errado. Está usando% c e não% s, então não há bug; apenas imprime a letra minúscula x. Além disso, sua afirmação subseqüente de que um ponteiro é do tipo int está errada e é um péssimo conselho para dar a um programador C inexperiente com ponteiros.
R .. GitHub Pare de ajudar o gelo
13
-1 Você começou bem, mas o primeiro exemplo está errado. Não, não é o mesmo. No primeiro caso, aé um ponteiro e, no segundo caso, aé uma matriz. Eu já mencionei isso? Não é o mesmo! Verifique você mesmo: compare o tamanho de (a), tente atribuir um novo endereço a uma matriz. Isso não vai funcionar.
sellibitze
42
char* a = "Hello";e char a[] = "Hello";não são iguais, são bem diferentes. Um declara um ponteiro e o outro uma matriz. Experimente a sizeofe você verá a diferença.
Patrick Schlüter
12
"Não é errado ou ilegal executar esta declaração printf". Isso está completamente errado. Essa declaração printf tem um comportamento indefinido. Em muitas implementações, isso causará uma violação de acesso. Na verdade, os ponteiros não são do tipo int, são realmente ponteiros (e nada mais).
Mankarse
19
-1, você entendeu muitos fatos errados aqui e eu simplesmente digo que você não merece a quantidade de votos positivos ou o status de resposta aceita.
asveikau
50

Um motivo para usar ponteiros é para que uma variável ou um objeto possa ser modificado em uma função chamada.

Em C ++, é uma prática melhor usar referências do que ponteiros. Embora as referências sejam essencialmente indicadores, o C ++, em certa medida, oculta o fato e faz parecer que você está passando por valor. Isso facilita a alteração da maneira como a função de chamada recebe o valor sem precisar modificar a semântica de transmiti-lo.

Considere os seguintes exemplos:

Usando referências:

public void doSomething()
{
    int i = 10;
    doSomethingElse(i);  // passes i by references since doSomethingElse() receives it
                         // by reference, but the syntax makes it appear as if i is passed
                         // by value
}

public void doSomethingElse(int& i)  // receives i as a reference
{
    cout << i << endl;
}

Usando ponteiros:

public void doSomething()
{
    int i = 10;
    doSomethingElse(&i);
}

public void doSomethingElse(int* i)
{
    cout << *i << endl;
}
trshiv
fonte
16
Provavelmente, é uma boa idéia mencionar que as referências são mais seguras, pois você não pode passar uma referência nula.
SpoonMeiser 02/10/08
26
Sim, essa é provavelmente a maior vantagem do uso de referências. Obrigado por apontar isso. Sem trocadilhos :)
trshiv
2
Você certamente pode passar referência nula. Não é tão fácil quanto passar um ponteiro nulo.
n0rd
11
concordo com @ n0rd. Se você acha que não pode passar uma referência nula, está errado. É mais fácil passar uma referência pendente do que uma referência nula, mas, no final das contas, você pode fazer isso com bastante facilidade. As referências não são balas de prata que protegem um engenheiro de um tiro no próprio pé. Veja ao vivo .
precisa saber é o seguinte
2
@ n0rd: Fazer isso é um comportamento explicitamente indefinido.
Daniel Kamil Kozar
42
  1. Os ponteiros permitem que você consulte o mesmo espaço na memória de vários locais. Isso significa que você pode atualizar a memória em um local e a alteração pode ser vista em outro local no seu programa. Você também economizará espaço ao compartilhar componentes em suas estruturas de dados.
  2. Você deve usar ponteiros em qualquer lugar em que precise obter e passar o endereço para um local específico na memória. Você também pode usar ponteiros para navegar nas matrizes:
  3. Uma matriz é um bloco de memória contígua que foi alocado com um tipo específico. O nome da matriz contém o valor do ponto inicial da matriz. Quando você adiciona 1, isso leva você ao segundo ponto. Isso permite escrever loops que incrementam um ponteiro que desliza a matriz sem ter um contador explícito para uso no acesso à matriz.

Aqui está um exemplo em C:

char hello[] = "hello";

char *p = hello;

while (*p)
{
    *p += 1; // increase the character by one

    p += 1; // move to the next spot
}

printf(hello);

impressões

ifmmp

porque pega o valor de cada caractere e o incrementa em um.

Kyle Cronin
fonte
because it takes the value for each character and increments it by one. Está na representação ascii ou como?
Eduardo S.
28

Os ponteiros são uma maneira de obter uma referência indireta para outra variável. Em vez de manter o valor de uma variável, eles informam seu endereço . Isso é particularmente útil ao lidar com matrizes, pois, ao usar um ponteiro para o primeiro elemento de uma matriz (seu endereço), você pode encontrar rapidamente o próximo elemento, incrementando o ponteiro (para o próximo endereço).

A melhor explicação sobre ponteiros e aritmética de ponteiros que eu li está na The C Programming Language da K&R . Um bom livro para começar a aprender C ++ é o C ++ Primer .

Bill the Lizard
fonte
11
obrigado! finalmente, uma explicação prática dos benefícios do uso da pilha! um ponteiro para posicionar em uma matriz também melhora o desempenho acessando os valores @ e relativos ao ponteiro?
Esta é provavelmente a melhor explicação que li. as pessoas têm uma maneira de "complicar demais" as coisas :)
Detilium 21/03
23

Deixe-me tentar responder a isso também.

Os ponteiros são semelhantes às referências. Em outras palavras, não são cópias, mas uma maneira de se referir ao valor original.

Antes de qualquer coisa, um lugar em que você normalmente precisará usar muito os ponteiros é quando está lidando com hardware incorporado . Talvez você precise alternar o estado de um pino de E / S digital. Talvez você esteja processando uma interrupção e precise armazenar um valor em um local específico. Você entendeu a foto. No entanto, se você não está lidando com hardware diretamente e está apenas se perguntando sobre quais tipos usar, continue a ler.

Por que usar ponteiros em vez de variáveis ​​normais? A resposta fica mais clara quando você lida com tipos complexos, como classes, estruturas e matrizes. Se você usar uma variável normal, poderá acabar fazendo uma cópia (os compiladores são inteligentes o suficiente para evitar isso em algumas situações e o C ++ 11 também ajuda, mas ficaremos longe dessa discussão por enquanto).

Agora, o que acontece se você deseja modificar o valor original? Você poderia usar algo como isto:

MyType a; //let's ignore what MyType actually is right now.
a = modify(a); 

Isso funcionará bem e, se você não souber exatamente por que está usando ponteiros, não deverá usá-los. Cuidado com o motivo "provavelmente são mais rápidos". Execute seus próprios testes e, se eles realmente forem mais rápidos, use-os.

No entanto, digamos que você esteja resolvendo um problema em que precisa alocar memória. Ao alocar memória, é necessário desalocá-la. A alocação de memória pode ou não ser bem-sucedida. É aqui que os ponteiros se tornam úteis - permitem testar a existência do objeto que você alocou e permitem acessar o objeto para o qual a memória foi alocada, retirando a referência do ponteiro.

MyType *p = NULL; //empty pointer
if(p)
{
    //we never reach here, because the pointer points to nothing
}
//now, let's allocate some memory
p = new MyType[50000];
if(p) //if the memory was allocated, this test will pass
{
    //we can do something with our allocated array
    for(size_t i=0; i!=50000; i++)
    {
        MyType &v = *(p+i); //get a reference to the ith object
        //do something with it
        //...
    }
    delete[] p; //we're done. de-allocate the memory
}

Essa é a chave para o uso de ponteiros - as referências assumem que o elemento que você está referenciando já existe . Um ponteiro não.

A outra razão pela qual você usaria ponteiros (ou pelo menos acabaria tendo que lidar com eles) é porque eles são um tipo de dados que existia antes das referências. Portanto, se você acabar usando bibliotecas para fazer as coisas que você sabe que são melhores, você descobrirá que muitas dessas bibliotecas usam ponteiros em todo o lugar, simplesmente por quanto tempo elas estão por aí (muitas deles foram escritos antes de C ++).

Se você não usou nenhuma biblioteca, pode projetar seu código de maneira a evitar os ponteiros, mas, como os ponteiros são um dos tipos básicos da linguagem, quanto mais rápido você se sentir confortável com eles, mais portátil, suas habilidades em C ++ seriam.

Do ponto de vista da capacidade de manutenção, devo mencionar também que, quando você usa ponteiros, é necessário testar sua validade e lidar com o caso quando eles não são válidos, ou apenas assumir que eles são válidos e aceitar o fato de que seu programa falhará ou pior quando essa suposição for quebrada. Em outras palavras, sua escolha com ponteiros é introduzir complexidade de código ou mais esforços de manutenção quando algo quebra e você está tentando rastrear um bug que pertença a toda uma classe de erros que os ponteiros introduzem, como corrupção de memória.

Portanto, se você controla todo o seu código, fique longe de ponteiros e use referências, mantendo-os constantes quando puder. Isso forçará você a pensar sobre o tempo de vida de seus objetos e acabará mantendo seu código mais fácil de entender.

Lembre-se desta diferença: uma referência é essencialmente um ponteiro válido. Um ponteiro nem sempre é válido.

Estou dizendo que é impossível criar uma referência inválida? Não. É totalmente possível, porque o C ++ permite fazer quase qualquer coisa. É apenas mais difícil de fazer sem querer e você ficará surpreso com a quantidade de bugs não intencionais :)

Carl
fonte
Você pode escrever boas classes de wrapper para E / S mapeadas na memória com as quais você pode essencialmente evitar o uso de ponteiros.
Einpoklum 28/05/19
13

Aqui está uma visão um pouco diferente, mas perspicaz, sobre por que muitos recursos do C fazem sentido: http://steve.yegge.googlepages.com/tour-de-babel#C

Basicamente, a arquitetura de CPU padrão é uma arquitetura de Von Neumann, e é tremendamente útil poder se referir à localização de um item de dados na memória e fazer aritmética com ele em uma máquina dessas. Se você conhece alguma variante da linguagem assembly, verá rapidamente como isso é crucial no nível mais baixo.

O C ++ torna os ponteiros um pouco confusos, pois às vezes os gerencia para você e oculta seus efeitos na forma de "referências". Se você usa C direto, a necessidade de ponteiros é muito mais óbvia: não há outra maneira de fazer chamada por referência, é a melhor maneira de armazenar uma string, é a melhor maneira de iterar através de uma matriz, etc.

Dan Lenski
fonte
12

Um uso de ponteiros (não mencionarei coisas já abordadas nas postagens de outras pessoas) é acessar a memória que você não alocou. Isso não é muito útil para programação de PC, mas é usado na programação incorporada para acessar dispositivos de hardware mapeados na memória.

Nos velhos tempos do DOS, você costumava acessar a memória de vídeo da placa de vídeo diretamente, declarando um ponteiro para:

unsigned char *pVideoMemory = (unsigned char *)0xA0000000;

Muitos dispositivos incorporados ainda usam essa técnica.

MrZebra
fonte
Não é uma razão para usar um ponteiro - uma estrutura semelhante a uma extensão - que também possui o comprimento - é muito mais apropriado. Hoje em dia é gsl::span, e em breve será std::span.
Einpoklum 28/05/19
10

Em grande parte, os ponteiros são matrizes (em C / C ++) - são endereços na memória e podem ser acessados ​​como uma matriz, se desejado (em casos "normais").

Como são o endereço de um item, são pequenos: ocupam apenas o espaço de um endereço. Como são pequenos, enviá-los para uma função é barato. E então eles permitem que essa função funcione no item real em vez de em uma cópia.

Se você deseja fazer alocação dinâmica de armazenamento (como para uma lista vinculada), deve usar ponteiros, porque eles são a única maneira de recuperar a memória do heap.

Warren
fonte
8
Eu acho enganoso dizer que ponteiros são arrays. Realmente, os nomes de matrizes são ponteiros const para o primeiro elemento da matriz. Só porque você pode acessar um ponto arbitrário como se a sua um array não significa que ele é ... você pode ter uma violação de acesso :)
rmeador
2
Ponteiros não são matrizes. Seção Leia 6 do FAQ comp.lang.c .
Keith Thompson
Ponteiros não são realmente matrizes. Além disso, também não há muito uso em matrizes brutas - certamente não depois do C ++ 11 e std::array.
Einpoklum 28/05/19
@einpoklum - os ponteiros estão próximos o suficiente para que as matrizes sejam equivalentes nas operações de referência e iterando através das matrizes :) .... também - C ++ 11 estava a 3 anos do lançamento quando esta resposta foi escrita em 2008
warren
@warren: Os ponteiros não são matrizes nem estão próximos de matrizes, eles simplesmente se deterioram em matrizes. É pedagogicamente inapropriado dizer às pessoas que elas são semelhantes. Além disso, você certamente pode ter referências a matrizes, que não são do mesmo tipo que ponteiros e mantém as informações de tamanho; veja aqui
einpoklum
9

Os ponteiros são importantes em muitas estruturas de dados cujo design requer a capacidade de vincular ou encadear um "nó" a outro com eficiência. Você não "escolheria" um ponteiro sobre um tipo de dados normal, como float, eles simplesmente têm finalidades diferentes.

Os ponteiros são úteis quando você exige alto desempenho e / ou espaço de memória compacto.

O endereço do primeiro elemento em sua matriz pode ser atribuído a um ponteiro. Isso permite acessar diretamente os bytes alocados subjacentes. O objetivo de uma matriz é evitar que você precise fazer isso.

Cinza
fonte
9

Uma maneira de usar ponteiros sobre variáveis ​​é eliminar a duplicação de memória necessária. Por exemplo, se você tiver algum objeto grande e complexo, poderá usar um ponteiro para apontar para essa variável para cada referência feita. Com uma variável, você precisa duplicar a memória para cada cópia.

Jason
fonte
Essa é uma razão para usar referências (ou no máximo - wrappers de referência), não ponteiros.
Einpoklum 28/05/19
6

No C ++, se você quiser usar o polimorfismo de subtipo , precisará usar ponteiros. Veja este post: Polimorfismo C ++ sem ponteiros .

Realmente, quando você pensa sobre isso, isso faz sentido. Quando você usa o polimorfismo de subtipo, no final das contas, não sabe antecipadamente qual implementação do método por classe ou subclasse será invocada porque você não sabe qual é a classe real.

Essa ideia de ter uma variável que contém um objeto de uma classe desconhecida é incompatível com o modo padrão (sem ponteiro) do C ++ de armazenar objetos na pilha, onde a quantidade de espaço alocado corresponde diretamente à classe. Nota: se uma classe tiver 5 campos de instância versus 3, mais espaço precisará ser alocado.


Observe que, se você estiver usando '&' para passar argumentos por referência, o indirection (ou seja, ponteiros) ainda estará envolvido nos bastidores. O '&' é apenas um açúcar sintático que (1) poupa o trabalho de usar a sintaxe do ponteiro e (2) permite que o compilador seja mais rigoroso (como proibir ponteiros nulos).

Sildoreth
fonte
Não, você não precisa usar ponteiros - você pode usar referências. E quando você escreve "ponteiros estão envolvidos nos bastidores" - isso não faz sentido. gotoas instruções também são usadas nos bastidores - nas instruções da máquina de destino. Ainda não reivindicamos usá-los.
Einpoklum 28/05/19
@ einpoklum-reinstateMonica Se você tiver um conjunto de objetos em que deseja atuar, atribua cada elemento a uma variável temporária e chame um método polimórfico nessa variável, sim, você PRECISA de um ponteiro, pois não pode refazer uma referência.
Sildoreth
Se você tiver uma referência de classe base a uma classe derivada e chamar um método virtual nessa referência, a substituição da classe derivada será chamada. Estou errado?
Einpoklum 12/12/19
@ einpoklum-reinstateMonica Isso está correto. Mas você não pode alterar qual objeto é referenciado. Portanto, se você estiver repetindo uma lista / conjunto / matriz desses objetos, uma variável de referência não funcionará.
Sildoreth 12/12/19
5

Porque copiar objetos grandes em todos os lugares desperdiça tempo e memória.

ninguém
fonte
4
E como os ponteiros ajudam nisso? Eu acho que uma pessoa vindo de Java ou .Net não sabe a diferença entre a pilha e a pilha, assim que esta resposta é bastante inútil ..
Mats Fredriksson
Você pode passar por referência. Isso impedirá a cópia.
Martin York
11
@MatsFredriksson - Em vez de passar (copiar) uma grande estrutura de dados e copiar o resultado novamente, basta apontar para onde ela está na RAM e modificá-la diretamente.
John U
Portanto, não copie objetos grandes. Ninguém disse que você precisa de indicadores para isso.
Einpoklum 28/05/19
5

Aqui está minha resposta, e não prometerei ser um especialista, mas achei os indicadores excelentes em uma das minhas bibliotecas que estou tentando escrever. Nesta biblioteca (é uma API gráfica com OpenGL :-)), você pode criar um triângulo com objetos de vértice passados ​​para eles. O método draw pega esses objetos triangulares e desenha-os com base nos objetos de vértice que eu criei. Bem, está tudo bem.

Mas e se eu alterar uma coordenada de vértice? Movê-lo ou algo com moveX () na classe de vértice? Bem, ok, agora eu tenho que atualizar o triângulo, adicionando mais métodos e desempenho está sendo desperdiçado, porque eu tenho que atualizar o triângulo toda vez que um vértice se move. Ainda não é grande coisa, mas não é tão bom assim.

Agora, e se eu tiver uma malha com toneladas de vértices e toneladas de triângulos, e a malha estiver girando, se movendo e assim por diante. Vou ter que atualizar todos os triângulos que usam esses vértices, e provavelmente todos os triângulos da cena, porque eu não saberia quais usam quais vértices. Isso exige muito computador, e se eu tiver várias malhas sobre uma paisagem, oh Deus! Estou com problemas, porque estou atualizando todos os triângulos, quase todos os quadros, porque esses vértices estão mudando o tempo todo!

Com ponteiros, você não precisa atualizar os triângulos.

Se eu tivesse três * objetos de vértice por classe de triângulo, não apenas estou economizando espaço porque um zilhão de triângulos não possui três objetos de vértice que são grandes, mas também esses ponteiros sempre apontam para os vértices a que se destinam, não importa com que frequência os vértices mudam. Como os ponteiros ainda apontam para o mesmo vértice, os triângulos não mudam e o processo de atualização é mais fácil de lidar. Se eu confundi você, não duvido, não finjo ser um especialista, apenas jogando meus dois centavos na discussão.

Jeremy Hahn
fonte
4

A necessidade de ponteiros na linguagem C é descrita aqui

A idéia básica é que muitas limitações na linguagem (como usar matrizes, seqüências de caracteres e modificar várias variáveis ​​em funções) podem ser removidas através da manipulação com os locais de memória dos dados. Para superar essas limitações, ponteiros foram introduzidos em C.

Além disso, também é visto que, usando ponteiros, você pode executar seu código mais rapidamente e economizar memória nos casos em que passa tipos de big data (como uma estrutura com muitos campos) para uma função. Fazer uma cópia desses tipos de dados antes da passagem levaria tempo e consumiria memória. Essa é outra razão pela qual os programadores preferem ponteiros para tipos de big data.

PS: Consulte o link fornecido para obter uma explicação detalhada com o código de exemplo.

vaibhav kumar
fonte
A pergunta é sobre C ++, esta resposta é sobre C.
einpoklum
não, a pergunta está marcada com c AND c ++. Talvez a tag c seja irrelevante, mas está aqui desde o início.
Jean-François Fabre
3

Em java e C #, todas as referências a objetos são ponteiros, o que acontece com o c ++ é que você tem mais controle sobre onde aponta os ponteiros. Lembre-se Com grande poder vem grande responsabilidade.

Marioh
fonte
1

Em relação à sua segunda pergunta, geralmente você não precisa usar ponteiros durante a programação, no entanto, há uma exceção a isso e é quando você cria uma API pública.

O problema com construções em C ++ que as pessoas geralmente usam para substituir ponteiros depende muito do conjunto de ferramentas que você usa, o que é bom quando você tem todo o controle necessário sobre o código-fonte; no entanto, se você compilar uma biblioteca estática com o visual studio 2008, por exemplo e tente usá-lo no visual studio 2010, você receberá vários erros de vinculador porque o novo projeto está vinculado a uma versão mais recente do STL que não é compatível com versões anteriores. As coisas ficam ainda mais desagradáveis ​​se você compilar uma DLL e fornecer uma biblioteca de importação que as pessoas usem em um conjunto de ferramentas diferente porque, nesse caso, seu programa falhará mais cedo ou mais tarde, sem motivo aparente.

Portanto, com a finalidade de mover grandes conjuntos de dados de uma biblioteca para outra, você pode considerar atribuir um ponteiro para uma matriz para a função que deve copiar os dados, se não desejar forçar outras pessoas a usar as mesmas ferramentas que você usa . A parte boa disso é que nem precisa ser uma matriz no estilo C, você pode usar um std :: vector e dar o ponteiro, fornecendo o endereço do primeiro elemento & vector [0], por exemplo, e usar o std :: vector para gerenciar a matriz internamente.

Outro bom motivo para usar ponteiros no C ++ novamente está relacionado às bibliotecas, considere ter uma dll que não pode ser carregada quando o programa for executado; portanto, se você usar uma biblioteca de importação, a dependência não será satisfeita e o programa trava. Este é o caso, por exemplo, quando você fornece uma API pública em uma DLL ao lado do seu aplicativo e deseja acessá-lo a partir de outros aplicativos. Nesse caso, para usar a API, você precisa carregar a dll a partir de sua localização (geralmente está em uma chave do Registro) e, em seguida, é necessário usar um ponteiro de função para poder chamar funções dentro da DLL. Às vezes, as pessoas que fazem a API são boas o suficiente para fornecer um arquivo .h que contém funções auxiliares para automatizar esse processo e fornecer todos os ponteiros de função necessários,

Radu Chivu
fonte
1
  • Em alguns casos, os ponteiros de função são necessários para usar funções que estão em uma biblioteca compartilhada (.DLL ou .so). Isso inclui executar coisas entre idiomas, onde muitas vezes é fornecida uma interface DLL.
  • Fazendo compiladores
  • Fazendo calculadoras científicas, onde você tem um mapa de vetor ou string de ponteiros de função?
  • Tentando modificar diretamente a memória de vídeo - criando seu próprio pacote gráfico
  • Fazendo uma API!
  • Estruturas de dados - ponteiros de link de nó para árvores especiais que você está criando

Existem várias razões para apontar. Ter o nome C manipulado especialmente é importante nas DLLs se você deseja manter a compatibilidade entre idiomas.

Jim Michaels
fonte