Peguei o teu código e dei uma alterada nele para que ele funcione como deve. Abaixo, tentarei explicar como tudo funciona.
#include <stdio.h>
#define TAMANHO 3
int soma(int nums[], int tamanho) {
int total = 0;
for (int i = 0; i < tamanho; i++) {
total += nums[i];
printf("%d\n", nums[i]);
}
return total;
}
int main(int argc, char *argv[]) {
// Use uma macro com o valor do tamanho, dessa forma, se precisar
// mudar o tamanho, só muda em um lugar, na definição da macro
int nums[TAMANHO];
// Se o array for grande, e a lógica de inicialização simples,
// inicialize com um loop. Veja mais abaixo a forma ideal
// de definir arrays de tamanho pequeno
for (int i = 0; i < TAMANHO; i++)
nums[i] = (i + 1) * 10;
int total = soma(nums, TAMANHO);
}
Em C, arrays são ponteiros implíticos, ou seja, o nome refere-se à posição de memória do primeiro elemento, o índice 0. Como o compilador sabe o tamanho que cada tipo de dado ocupa em memória, e todos os elementos do array estão em posições adjacentes de memória, ele percorre o array por meio de aritmética de ponteiros. Segue um exemplo de código que demonstra isso:
#include <stdio.h>
#define TAMANHO 10
int main(int argc, char *argv[]) {
int array[TAMANHO];
int *ptr = array;
// Repare que estou inicializando o array por meio de ptr
for (int i = 0; i < TAMANHO; i++)
*(ptr + i) = i*i;
// Verifique que funciona
for (int i = 0; i < TAMANHO; i++)
printf("%d, ", array[i]);
return 0;
}
Aqui vem uma tecnicalidade de arquitetura de computadores!
Um programa é composto de segmentos de memória distintos, sendo eles, do endereço mais alto para o mais baixo:
- Pilha (Stack): onde parâmetros de funções são alocados
- Heap: de onde se obtém memória dinâmicamente por meio de malloc ou calloc
- Dados: segmento estático de dados, ou seja, cujo tipo, dimensão e escopo são conhecidos em tempo de compilação
- Texto: instruções que compõem o programa (sim, instruções possuem endereço!)
Em C, arrays são instanciados estaticamente --- leia-se tempo de compilação --- portanto residem no segmento de dados. Por este motivo, o compilador tem de saber, além do tipo, o tamanho do array. Uma das formas abaixo deve ser utilizada para declarar um array:
// O tamanho é definido implicitamente pelo compilador, e
// os elementos do array inicializados
int array[] = { 10, 20, 30 };
// O tamanho é definido explicitamente, e os elementos não são inicializados
int array[3];
// Uma forma elegante do padrão C99 para inicializar todos os
// elementos do array com valor nulo. Válido também para estruturas
int array[3] = { 0 };
Em C, por padrão, parâmetros de funções são sempre passados por valor, ou seja, é criada uma cópia na pilha para que a função use. Consequentemente, alterações realizadas dentro das funções não geram side-effects. Repare no código abaixo, o valor de i não se alterou após a execução de func.
#include <stdio.h>
void func(int arg) {
arg += 10;
}
int main(int argc, char *argv[]) {
int i = 5;
printf("%d\n", i);
func(i);
printf("%d\n", i);
return 0;
}
Nem sempre, entretanto, esse é o comportamento desejado pelo programador. Seja por eficiência, pois copiar estruturas grandes é custoso, seja por conveniência, pois deseja-se que as alterações nos dados passados às funções sejam efetivamente guardadas. Nessas situações, desejamos realizar uma passagem por referência. Repare no código abaixo:
#include <stdio.h>
void func(int *arg) {
*arg += 10;
}
int main(int argc, char *argv[]) {
int i = 5;
printf("%d\n", i);
func(&i);
printf("%d\n", i);
return 0;
}
Esse --- juntamente às callbacks, alocação dinâmica de memória, criação de TADs e programação genérica --- é o uso de ponteiros na linguagem C! Para qualquer outra finalidade, uma vez que não seja estritamente necessário, evite usar ponteiros, seu uso dificulta a legibilidade do programa conforme o nível de indireção aumenta, e erros relacionados a ponteiros costumam ser difícies de encontrar.
Adendo:
Atenção! Lembra que arrays são ponteiros implícitos? Pois bem, isso significa que seu conteúdo é sempre passado por referência. Portanto, alterações realizadas dentro de uma função chamada alteram o array na função chamadora.