Quais problemas de programação são melhor resolvidos usando ponteiros? [fechadas]

57

Bom, eu basicamente entendo como usar ponteiros, mas não como usá-los para fazer melhor programação.

Quais são bons projetos ou problemas para resolver envolvendo o uso de ponteiros para que eu possa compreendê-los melhor?

    
por dysoco 11.09.2011 / 23:33
fonte

17 respostas

68

Manipular grandes quantidades de dados na memória é onde os ponteiros realmente brilham.

Passar um objeto grande por referência é equivalente a apenas passar um número antigo simples. Você pode manipular as partes necessárias diretamente, ao invés de copiar um objeto, alterá-lo e, em seguida, passar a cópia para ser colocada no lugar do original.

    
por 17.09.2011 / 01:43
fonte
44

O conceito de ponteiro permite consultar dados por endereço sem duplicar o armazenamento de dados. Essa abordagem permite escrever algoritmos eficientes como:

  1. Classificando
    Ao mover dados em um algoritmo de classificação, você pode mover o ponteiro em vez dos dados em si - pense em classificar milhões de linhas em uma cadeia de 100 caracteres; você economiza muitos movimentos de dados desnecessários.

  2. Listas vinculadas
    Você pode armazenar a localização do item seguinte e / ou anterior e não os dados inteiros associados ao registro.

  3. Passando parâmetros
    Nesse caso, você passa o endereço dos dados em vez dos dados em si. Novamente, pense em um algoritmo de compactação de nome que é executado em milhões de linhas.

O conceito pode ser estendido a estruturas de dados, como bancos de dados relacionais, em que um ponteiro é semelhante a uma chave estrangeira . Algumas linguagens não incentivam o uso de ponteiros como C # e COBOL.

Exemplos podem ser encontrados em muitos lugares, como:

A postagem a seguir pode ser relevante de alguma forma:

por 23.05.2017 / 14:40
fonte
29

Surpreende-me que nenhuma outra resposta tenha mencionado isso: os ponteiros permitem que você crie estruturas de dados não contíguas e não-lineares, em que um elemento pode estar relacionado a vários outros de formas complexas.

Listas interligadas (individual, duplamente e circularmente ligadas), árvores (vermelho-preto, AVL, trie, binário, particionamento de espaço ...) e gráficos são exemplos de estruturas que podem ser construídas mais naturalmente em termos de referências que apenas valores.

    
por 11.09.2011 / 22:20
fonte
8

Uma maneira simples é o polimorfismo. O polimorfismo só funciona com ponteiros.

Além disso, você usa ponteiros sempre que precisar de alocação de memória dinâmica. Em C, isso geralmente acontece quando você precisa armazenar dados em uma matriz, mas não sabe o tamanho em tempo de compilação. Você então chamaria malloc para alocar a memória e um ponteiro para acessá-la. Além disso, quer você saiba disso ou não, ao usar uma matriz, você está usando ponteiros.

for(int i = 0; i < size; i++)
   std::cout << array[i];

é o equivalente de

for(int i = 0; i < size; i++)
   std::cout << *(array + i);

Esse conhecimento permite que você faça coisas muito legais, como copiar uma matriz inteira em uma linha:

while( (*array1++ = *array2++) != '
for(int i = 0; i < size; i++)
   std::cout << array[i];
')

Em c ++, você usa new para alocar memória para um objeto e armazená-lo em um ponteiro. Você faz isso sempre que precisar criar um objeto durante o tempo de execução, em vez de durante o tempo de compilação (ou seja, um método cria um novo objeto e o armazena em uma lista).

Para entender melhor os ponteiros:

  1. Encontre alguns projetos que funcionam com strings e arrays tradicionais.
  2. Encontre alguns projetos que usam herança.

  3. Aqui está o projeto que eu fiz::

Leia em duas matrizes n x n de um arquivo e execute as operações básicas do espaço vetorial nelas e imprima seu resultado na tela.

Para fazer isso, você precisa usar arrays dinâmicos e referir-se a seus arrays por ponteiros, já que você terá dois arrays de arrays (arrays dinâmicos multidimensionais). Depois de concluir o projeto, você terá uma boa ideia de como usar ponteiros.

    
por 11.09.2011 / 22:24
fonte
8

Para entender realmente por que os ponteiros são importantes, você precisa entender a diferença entre a alocação de heap e a alocação de pilha.

O seguinte é um exemplo de uma alocação de pilha:

struct Foo {
  int bar, baz
};

void foo(void) {
  struct Foo f;
}

Os objetos alocados na pilha existem apenas durante a execução da função atual. Quando a chamada para foo sai do escopo, a variável f .

Um caso em que isso se torna um problema é quando você precisa retornar algo diferente de um tipo integral de uma função (por exemplo, a estrutura Foo do exemplo acima).

Por exemplo, a seguinte função resultaria no chamado "comportamento indefinido".

struct Foo {
  int bar, baz
};

struct Foo *foo(void) {
  struct Foo f;
  return &f;
}

Se você quiser retornar algo como struct Foo * de uma função, o que realmente precisa é de uma alocação de heap:

struct Foo {
  int bar, baz
};

struct Foo *foo(void) {
  return malloc(sizeof(struct Foo));
}

A função malloc aloca um objeto no heap e retorna um ponteiro para esse objeto. Note que o termo "objeto" é usado frouxamente aqui, significando "algo" em vez de objeto no sentido de programação orientada a objeto.

O tempo de vida de objetos alocados em heap é controlado pelo programador. A memória para este objeto será reservada até que o programador a libere, ou seja, chamando free() ou até que o programa saia.

Editar : não percebi que essa questão é marcada como uma questão do C ++. Os operadores de C ++ new e new[] executam a mesma função que malloc . Os operadores delete e delete[] são análogos a free . Embora new e delete devam ser usados exclusivamente para alocar e liberar objetos C ++, o uso de malloc e free é perfeitamente legal no código C ++.

    
por 12.09.2011 / 01:25
fonte
4

Escreva qualquer projeto não-trivial em C e você terá que descobrir como / quando usar ponteiros. Em C ++, você utilizará principalmente objetos habilitados para RAII que gerenciam ponteiros internamente, mas em C, os ponteiros brutos têm um papel muito mais predominante. Quanto ao tipo de projeto que você deve fazer, pode ser qualquer coisa não trivial:

  • Um servidor web pequeno e simples
  • Ferramentas de linha de comando do Unix (less, cat, sort etc.)
  • Algum projeto real que você deseja fazer por si só e não apenas por aprender

Eu recomendo o último.

    
por 11.09.2011 / 21:59
fonte
3

Quase todos os problemas de programação que podem ser resolvidos com ponteiros podem ser resolvidos com outros tipos mais seguros de referências (não se referindo a referências C ++ , mas o conceito geral de CS de ter uma variável se refere a o valor dos dados armazenados em outro lugar).

Ponteiros por ser uma implementação específica de baixo nível de referências, onde você pode manipular endereços de memória diretamente são muito poderosas, mas podem ser um pouco perigosas de usar (por exemplo, apontar para locais de memória fora do programa).

O benefício de usar ponteiros diretamente é que eles serão um pouco mais rápidos se não precisarem fazer nenhuma verificação de segurança. Idiomas como Java, que não implementam diretamente ponteiros estilo C, sofrerão um pequeno impacto no desempenho, mas reduzirão muitos tipos de situações difíceis de depurar.

Quanto a por que você precisa de indireção, a lista é bem longa, mas essencialmente as duas ideias principais são:

  1. A cópia de valores de objetos grandes é lenta e fará com que o objeto seja armazenado na RAM duas vezes (potencialmente muito caro), mas a cópia por referência é quase instantânea, usando apenas alguns bytes de RAM (para o endereço). Por exemplo, digamos que você tenha aproximadamente 1000 objetos grandes (cada um com cerca de 1 MB de RAM) em memória, e seu usuário precisa poder selecionar o objeto atual (que será usado pelo usuário). Ter uma variável selected_object que é uma referência a um dos objetos é muito mais eficiente do que copiar o valor do objeto atual em uma nova variável.
  2. Ter estruturas de dados complicadas que se referem a outros objetos, como listas ou árvores vinculadas, em que cada item na estrutura de dados se refere a outros itens na estrutura de dados. O benefício de se referir a outros itens na estrutura de dados significa que você não precisa mover todos os itens da lista na memória apenas porque você inseriu um novo item no meio da lista (pode ter inserções de hora constantes). / li>
por 12.09.2011 / 16:31
fonte
2

A manipulação de imagens em nível de pixel é quase sempre mais fácil e rápida usando ponteiros. Às vezes só é possível usar ponteiros.

    
por 11.09.2011 / 22:03
fonte
1

Ponteiros são usados em tantas linguagens de programação abaixo da superfície sem incomodar o usuário. C / C ++ apenas dá acesso a eles.

Quando usá-los: Sempre que possível, porque a cópia de dados é ineficiente. Quando não usá-los: quando você quiser duas cópias que podem ser alteradas individualmente. (O que basicamente acabará copiando o conteúdo de object_1 para outro lugar na memória e retornando um ponteiro - desta vez apontando para object_2)

    
por 12.09.2011 / 03:45
fonte
1

Os ponteiros são uma parte essencial para qualquer implementação da estrutura de dados em C e as estruturas de dados são uma parte essencial de qualquer programa não trivial.

Se você gostaria de saber por que os ponteiros são tão vitais, sugiro aprender o que é uma lista vinculada e tentar escrever um sem usar ponteiros. Eu não defini um desafio impossível para você (DICA: ponteiros são usados para referenciar locais na memória, como você faz referência a coisas em matrizes?).

    
por 12.09.2011 / 08:05
fonte
0

Como um exemplo da vida real, crie um livro de pedidos com limite.

O feed do ITCH 4.1, por exemplo, tem o conceito de "substituir" pedidos, onde os preços (e, portanto, a prioridade) podem mudar. Você quer ser capaz de pegar ordens e movê-las para outro lugar. A implementação de uma fila de duas extremidades com ponteiros torna a operação muito fácil.

    
por 12.09.2011 / 05:31
fonte
0

Examinando os vários sites do StackExchange, percebo que é muito em voga fazer uma pergunta como essa. Correndo o risco de críticas e desvantagens, serei honesto. Isso não é para trollar ou inflamar, eu só estou querendo ajudar, dando uma avaliação honesta da questão.

E essa avaliação é a seguinte: Essa é uma pergunta muito estranha de se fazer um programador C. Quase tudo o que diz é "eu não sei C." Se eu analisar um pouco mais e mais cinicamente, há um tom de subseqüente a essa "pergunta": "Existe algum atalho que eu possa tomar para rapidamente e de repente adquirir o conhecimento de um programador C experiente, sem dedicar tempo? para estudo independente? " Qualquer "resposta" que alguém possa dar não é um substituto para ir e fazer o trabalho de compreensão do conceito subjacente e seu uso.

Eu sinto que é mais construtivo aprender C bem, em primeira mão, do que ir na web e perguntar isso para as pessoas. Quando você conhece C bem, você não se incomodará em fazer perguntas como esta, será como perguntar "que problemas são melhor resolvidos usando uma escova de dentes?"

    
por 12.09.2011 / 07:33
fonte
0

Embora os ponteiros realmente brilhem ao trabalhar com grandes objetos de memória, ainda existe uma maneira de fazer o mesmo sem eles.

O ponteiro é absolutamente essencial para a chamada programação dinâmica , é quando você não sabe quanta memória você precisará antes de seu programa ser executado. Na programação dinâmica, você pode solicitar pedaços de memória durante o tempo de execução e colocar seus próprios dados naqueles - assim, você precisa de um ponteiro ou referências (a diferença não é importante aqui) para poder trabalhar com esses blocos de dados.

Contanto que você possa reivindicar determinada memória durante o tempo de execução e colocar seus dados na memória recém-adquirida, você poderá fazer o seguinte:

  1. Você pode ter estruturas de dados auto-extensíveis. Essas são estruturas que podem se estender, reivindicando memória adicional, desde que sua capacidade se esgote. A propriedade-chave de toda estrutura auto-extensível é que ela consiste em pequenos blocos de memória (nós nomeados, itens de lista, etc., dependendo da estrutura) e cada bloco contém referências a outro (s) bloco (s). Essas estruturas "vinculadas" constroem a maioria dos tipos de dados modernos: gráficos, árvores, listas, etc.

  2. Você pode programar usando o paradigma OOP (Object-Oriented Programming). O OOP inteiro é baseado no uso não de variáveis diretas, mas de referências a instâncias de classes (objetos denominados) e de manipulá-las. Nenhuma instância única pode existir sem ponteiros (mesmo que seja possível usar classes somente estáticas mesmo sem ponteiros, isso é uma exceção).

por 12.09.2011 / 08:43
fonte
0

Engraçado, acabei de responder uma pergunta sobre o C ++ e falei sobre ponteiros.

Versão curta é NUNCA precisa de ponteiros a menos que 1) a biblioteca que você está usando o force 2) Você precisa de uma referência anulável.

Se você precisa de um array, list, string etc, basta colocá-lo na pilha e usar um objeto stl. Retornar ou passar objetos stl é rápido (fato desmarcado) porque eles têm código interno que copia um ponteiro em vez de um objeto e copia somente os dados se você gravar nele. Este é o C ++ regular, nem mesmo o novo C ++ 11, que facilitará os escritores da biblioteca.

Sua pergunta pode ser respondida nesta parte

Se você usar um ponteiro, verifique se ele está em uma dessas duas condições. 1) Você está passando a entrada que pode ser anulável. Um exemplo é um nome de arquivo opcional. 2) Se você quer dar a dona. Como se você passasse ou devolvesse o ponteiro, você não tem NENHUMA cópia dele restante nem usa o ponteiro que você deu

ptr=blah; func(ptr); //never use ptr again for here on out.

Mas eu não usei ponteiros ou ponteiros inteligentes por um tempo muito longo e eu perfilei meu aplicativo. Corre muito rápido.

NOTA ADICIONAL: Eu noto que escrevo meus próprios structs e os transmito. Então, como faço isso sem usar ponteiros? Não é um contêiner STL então passar por ref é lento. Eu sempre carrego minha lista de dados / deques / mapas e tal. Eu não me lembro de retornar objetos, a menos que fosse algum tipo de lista / mapa. Nem mesmo uma corda. Eu olhei para o código de objetos únicos e eu percebo que eu faço algo assim { MyStruct v; func(v, someinput); ... } void func(MyStruct&v, const D&someinput) { fillV; } , então eu praticamente retorno objetos (múltiplos) ou pré-alocar / passar em uma referência para preencher (único).

Agora, se você estava escrevendo você mesmo, você precisa usar ponteiros. Mas você não precisa. Deixe STL e possivelmente impulsionar se preocupar com isso. Você só precisa escrever dados e as soluções. Não recipientes para segurá-los;)

Espero que você nunca use ponteiros: D. Boa sorte em lidar com libs que o forçam a

    
por 12.09.2011 / 09:31
fonte
0

Os ponteiros são muito úteis para trabalhar com dispositivos mapeados na memória. Você pode definir uma estrutura que reflita (digamos) um registrador de controle, então atribua-o ao endereço do registrador de controle real na memória e manipule-o diretamente. Você também pode apontar diretamente para um buffer de transferência em um cartão ou chip, se o MMU o tiver mapeado no espaço de memória do sistema.

    
por 13.09.2011 / 12:36
fonte
0

Eu vejo ponteiros como meu dedo indicador, costumamos fazer algumas coisas:

  1. quando alguém lhe pede algo que você não pode carregar, como onde é a rua assim e assim, eu "apontaria" para essa rua, e é isso que fazemos no caso de argumentos por referência
  2. quando contamos ou percorremos algo, usamos o mesmo dedo, e é isso que fazemos em matrizes

por favor, perdoe esta pobre resposta

    
por 14.11.2011 / 05:11
fonte
0

Como sua pergunta é marcada com C ++, responderei sua pergunta para esse idioma.

Em C ++, há uma distinção entre ponteiros e referências, portanto, há dois cenários em que ponteiros (ou ponteiros inteligentes) são necessários para facilitar determinados comportamentos. Eles podem ser usados em outras circunstâncias, mas você pergunta como "é melhor usá-los" e, em todas as outras circunstâncias, há alternativas melhores.

1. Polimorfismo

Um ponteiro de classe base permite que você chame um método virtual que depende do tipo de objeto para o qual o ponteiro aponta.

2. Criando objetos persistentes

Os ponteiros são necessários ao criar um objeto dinamicamente (no heap, em vez de na pilha). Isso é necessário quando você deseja que o tempo de vida dos objetos seja maior que o escopo no qual ele é criado.

Em termos de "bons projetos ou problemas para resolver", como já foi dito aqui, qualquer projeto não-trivial fará uso de ponteiros.

    
por 01.12.2014 / 13:33
fonte