2
respostas

O que significa *num em C?

void soma(int* num, int a, int b) {
    *num = a + b;
}

não seria? (*num) = a + b;

2 respostas

Olá Silvio.

*num significa que num é um ponteiro para uma variável que armazenará os valores de a + b .

Neste caso não há diferença entre usar *num ou (*num), uma vez que o operador "*" tem precedência sobre o operador de atribuição "=".

No caso de ponteiros para ponteiros, o uso dos parênteses se justifica, por exemplo:

(*num)->prox; em que o operador "->" tem precedência sobre o operador "*".

Quanto à necessidade de parênteses, como o operador de desreferenciação (*) tem precedência mais alta que o operador atribuição, não há necessidade. Para maiores detalhes, olhar a tabela

No entanto, vale a pena observar alguns pontos.

Nas linguagens de programação existem duas filosofias distintas sobre como tratar os parâmetros de funções: passagem por valor ou por referência. No primeiro caso, o conteúdo da variável é copiado na pilha, e qualquer alteração realizada no escopo da função é perdida após o retorno. No segundo caso, a própria variável é passada, o que significa que alterações no estado são visíveis mesmo após o retorno ao escopo da função chamadora.

Linguagens como C e Java tratam argumentos por valor. Em ambos os casos, não há sintaxe especial para referências, apenas formas de simular comportamento, diferentemente de linguagens como C++ e Rust, que possuem notação própria para isso.

Em um computador tudo se resume a memória. Para cada processo, o sistema operacional disponibiliza um bloco de endereçamento virtual, que começa no endereço 0x0. Um programa é executado em uma instância de um processo. Podemos entender um programa como um conjunto de segmentos sequenciais distintos de bytes, simplificadamente categorizados como: texto, dados, heap e pilha. Na arquitetura x86 o endereçamento segue a ordem previamente estabelecida, do menor para o maior endereço, sendo:

  1. Texto, também conhecido como segmento de código, contêm sequencias de instruções de máquina;
  2. Dados contêm variáveis globais;
  3. Heap é a área de memória usada para alocação dinâmica;
  4. Pilha armazena o contexto de execução de funções, incluindo parâmetros e variáveis locais.

A posição de memória de uma variável, instrução ou função é meramente o offset dela em relação à posição 0, contabilizado em palavras, que por sua vez é a medida nativa do processador. Um processador de 64 bits, tipicamente, possui palavras de 64 bits (8 bytes).

Em C, existe o conceito de ponteiro, que, diferentemete de varíaveis convencionais, apontam (isto é, armazenam) endereços de memória. A notação da linguagem C para ponteiros é a seguinte:

    int *ptr = NULL; // Declara um ponteiro de inteiros, e inicializa
                     // com NULL, ou seja, o endereço 0x0. 
                     // Importante! Nunca deixe um ponteiro não inicializado,
                     // bugs envolvendo ponteiros selvagens são difíceis de
                     // tratar.
    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
        int x = 20;	
        int *ptr = &x;
    
        printf("antes: %d\n", x);
        (*ptr)++;
        printf("depois: %d\n", x);
        return 0;
    }

Como você pode observar pelo programa anterior, a variável x foi modificada por meio de ptr.

C utiliza ponteiros para uma ampla gama de tarefas, como: alocação dinâmica de memória, callbacks, simulação de referências, operações em arrays, operações em arquivos, strings, estruturas de dados complexas, operações de baixo nível, etc.

Dado o exemplo da pegunta:

    void soma(int* num, int a, int b) {
        *num = a + b;
    }

a ulização do ponteiro num para a simulação de passagem por referências garante que qualquer alteração de estado dentro da função soma será refletido no valor da variável passada à função. Você já deve ter usado código semelhante a esse:

    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
        int x;
        printf("imprime uma mensagem na tela solicitando valor: ");
        scanf("%d", &x);
        
        // ...
        
        return 0;
    }

Note que na chamada à função scanf passamos &x (o endereço de x). Isso ocorre porque, do contrário, o valor de x não poderia ser alterado pela função.