void soma(int* num, int a, int b) {
*num = a + b;
}
não seria? (*num) = a + b;
void soma(int* num, int a, int b) {
*num = a + b;
}
não seria? (*num) = a + b;
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:
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.