AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 79553314
Accepted
Roee Zamir
Roee Zamir
Asked: 2025-04-03 23:04:29 +0800 CST2025-04-03 23:04:29 +0800 CST 2025-04-03 23:04:29 +0800 CST

Por que K&R dizem que ponteiros são preferíveis a matrizes como parâmetros de função?

  • 772

Da página 99 de K&R:

Capítulo 5.3 de K&R

"preferimos o último porque diz mais explicitamente que a variável é um ponteiro."

Preciso de algum esclarecimento sobre por que "dizer mais explicitamente que a variável é um ponteiro" teria alguma importância? Eu esperaria que o motivo fosse para o programa ser mais rápido, em vez de mais explícito, como declarado na página 97:

"A versão do ponteiro será, em geral, mais rápida, mas, pelo menos para os não iniciados, um pouco mais difícil de entender"

Mas nesse caso, por que a versão do ponteiro seria mais rápida? Se arr[i]for equivalente a isso, *(a+i)por que o programa seria mais rápido? É porque C não precisa converter o array para a versão do ponteiro?

c
  • 4 4 respostas
  • 774 Views

4 respostas

  • Voted
  1. Best Answer
    ikegami
    2025-04-03T23:29:59+08:002025-04-03T23:29:59+08:00

    Fora da lista de parâmetros, char s[]e char *ssão diferentes.

    void foo( void ) {
       char a[] = "abcdef";  // An array of 7 `char` elements.
       char *p = "abcdef";   // A pointer that points to a sequence of 7 `char` objects.
    }
    

    Em uma lista de parâmetros, char s[]e char *ssão 100% equivalentes por definição.

    void foo(
       char p1[],  // A pointer that points to a `char` object.
       char *p2    // A pointer that points to a `char` object.
    ) {
    }
    

    Ele está dizendo que, como sé um ponteiro, é mais claro usar char *s. Usar char s[], embora equivalente, pode enganar "os não iniciados" a pensar que é um array quando não é.

    Note que nem todo mundo concorda em sempre usar parâmetros char *sem vez de char s[]for. Estou apenas explicando a opinião expressa pelo livro, conforme solicitado.


    Como char s[]e char *ssão equivalentes em uma lista de parâmetros, não há diferença em desempenho. Suspeito que a passagem que você citou sobre desempenho foi tirada de um contexto diferente, um onde char s[]e char *snão são encontrados em uma lista de parâmetros.

    char *s = "abcdef";provavelmente será mais rápido char s[] = "abcdef";porque o primeiro é comumente implementado como um simples carregamento de um ponteiro para uma string existente na imagem binária, enquanto o último é comumente implementado como uma cópia de 7 bytes para a pilha.

    Mas isso não se aplica a parâmetros. Eles são 100% equivalentes lá.

    • 12
  2. Fe2O3
    2025-04-04T08:44:32+08:002025-04-04T08:44:32+08:00

    Passe algum tempo pensando na equivalência de duas versões frequentemente vistas de uma declaração de função:

        int main( int argc, char **argv ) {
        //
        int main( int argc, char *argv[] ) {
    

    Por "equivalência", para ambas as versões argvé, isoladamente, uma variável contendo um endereço de memória a ser interpretado como um ponteiro .

    Na primeira versão, o leitor entende argvque é um "ponteiro para um ponteiro para um char", mas aprendeu que o chararmazenamento é o primeiro byte de uma string C, e que o próximo ponteiro acessível ++argv(geralmente) apontará para a próxima string C, e assim por diante.

    A primeira é a notação compacta, e a função provavelmente avança o ponteiro argvà medida que lida com cada parâmetro da linha de comando sequencialmente.

        ...
        for( --argc; argc; argc-- ) { // clumsy, but worth pondering to learn
            char *param = *(++argv);
            ...
    

    Na segunda versão, a desreferenciação de argvé, talvez, um pouco mais explícita sobre a existência de uma matriz (de argcelementos que são, eles próprios, ponteiros) a ser encontrada naquele caminho.

    A segunda sugere que, em vez de simplesmente avançar o ponteiro argv, pode haver uma expectativa de que a posição de cada parâmetro da linha de comando seja significativa.
    Por exemplo: myrename foo bar sabe que o arquivo a ser renomeado sempre estará emargv[1]

        ...
        // Not shown: code that ensures there are two-and-only-two parameters.
        // It's up to the function (and caller) to not access outside of claimed memory.
        char *exeName = argv[0]; // name of this executable
        char *curName = argv[1];
        char *newName = argv[2];
        ...
    

    Como é frequentemente o caso, há muitas maneiras de esfolar um gato.
    Por causa dessa equivalência, o codificador pode escolher qualquer sintaxe que forneça a maior clareza no código. Eventualmente, você verá as sintaxes como intercambiáveis, e a escolha de qual usar terá pouca consequência (quando nenhum outro problema estiver presente).

    Dominar ponteiros é um dos poucos obstáculos para usar C (ou seus primos), mas é um requisito valioso para se tornar um bom programador.

    • 3
  3. Lundin
    2025-04-03T23:45:34+08:002025-04-03T23:45:34+08:00

    Preciso de alguns esclarecimentos sobre por que "dizer mais explicitamente que a variável é um ponteiro" teria alguma importância?

    Entender como arrays, sempre que usados ​​em expressões ou escritos como parâmetros de função, são ajustados ("decaimento") em um ponteiro para o primeiro elemento é uma das coisas clássicas com as quais todos que estão aprendendo C estão tendo dificuldades. Portanto, a versão array pode ser confusa, por exemplo:

    void func (int array[10]);
    

    Alguns podem pensar incorretamente que isso cria uma cópia do array passado ao mostrar 10 inteiros na pilha. Mas ele é ajustado para um ponteiro do primeiro elemento do array passado, e então é equivalente a int* array.


    A citação completa e o contexto de K&R 2ª edição:

    Qualquer operação que pode ser alcançada por subscrição de array também pode ser feita com ponteiros. A versão de ponteiro será, em geral, mais rápida, mas, pelo menos para os não iniciados, um pouco mais difícil de entender.

    Em primeiro lugar, a subscrição de arrays sempre envolve decaimento de arrays, então ela não pode ser usada com arrays; ela é sempre usada com ponteiros (decaídos).

    "A versão do ponteiro será em geral mais rápida" é simplesmente um absurdo total. Não há como nem mesmo o fanboy mais dogmático de K&R varrer essa declaração descaradamente incorreta para debaixo do tapete e salvar a cara dos autores.

    Compre um livro melhor, de preferência deste milênio.

    • 2
  4. Adrian McCarthy
    2025-04-04T02:08:18+08:002025-04-04T02:08:18+08:00

    Aqui está um pouco mais de contexto para a citação sobre a versão do ponteiro ser mais rápida:

    Qualquer operação que pode ser alcançada por subscrição de array também pode ser feita com ponteiros. A versão de ponteiro será, em geral, mais rápida, mas, pelo menos para os não iniciados, um pouco mais difícil de entender.

    E, algumas páginas depois:

    Há uma diferença entre um nome de array e um ponteiro que deve ser mantida em mente. Um ponteiro é uma variável... Mas um nome de array não é uma variável.

    [Meus números de página não correspondem, então devemos estar lendo edições diferentes.]

    Se você tem um nome de array e quer desreferenciar para um offset específico, primeiro você tem que (1) carregar o endereço do array em um registrador e (2) fazer a aritmética para chegar ao offset. Se você já tem um ponteiro para o primeiro elemento, então você efetivamente já fez o primeiro passo.

    Isso não importa para acessos únicos, mas pode ter importado para um algoritmo que faz acessos repetidos, seja sequencialmente ou saltando.

    Mas os detalhes são específicos para o hardware e o compilador, ambos os quais evoluíram muito desde que o escreveram. Ao longo dos anos, vi demonstrações comparando uma versão de indexação de array e uma versão de desreferenciação de ponteiro do mesmo algoritmo. Às vezes, a mais rápida era indexada, às vezes era por ponteiro. Conforme os anos passavam, a diferença era geralmente cada vez menos significativa.

    Ambos os métodos são válidos, e hoje em dia geralmente não há diferença de desempenho. É importante entender ambos. Mas ao decidir qual usar, use aquele que melhor expressa o algoritmo. A preferência de K&R pela notação de ponteiro é uma tentativa de lembrar ao leitor que a decadência de ponteiro acontece, e você pode ficar confuso se fingir que não acontece.

    • 2

relate perguntas

  • Multiplicação mais rápida que *

  • Usando uma macro para comprimento de string no especificador de formato scanf () em C

  • Como você pode definir o tipo de dados de #define para long double?

  • Ponteiros const incompatíveis

  • Mudança de cor não gradual no OpenGL

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve