Eu tenho o seguinte código. Chamar f1 gera segfault, mas não f2.
#include <stdlib.h>
#include <stdio.h>
void f1(unsigned char** arr)
{
unsigned char* p = *arr;
*p = 'h';
p++;
*p = '\0';
}
void f2(unsigned char* arr)
{
unsigned char* p = arr;
*p = 'h';
p++;
*p = '\0';
}
int main()
{
unsigned char a[31];
f1((unsigned char**)&a);
//f2(a);
printf("%s\n", a);
}
unsigned char**
é um ponteiro para um ponteiro para umunsigned char
.&a
retorna o endereço do arraya[]
. O tipo que&a
retorna éunsigned char (*)[31]
, nãounsigned char**
, e é por isso que você não pode simplesmente chamarf1(a)
which é uma incompatibilidade de tipo. Preste atenção nesse erro, é importante.&a
não retorna o endereço de um ponteiro, mas você está usando um typecast para induzir o compilador a pensar que sim, portanto, você está forçandof1()
o acesso a um endereço de memória inválido por meio de um ponteiro inválido, daí o segfault.IOW, você está pegando um ponteiro para array e convertendo-o em um ponteiro para ponteiro , o que não é. Dentro de
f1()
, a*arr
desreferência espera produzir umunsigned char*
ponteiro para um válidounsigned char
, mas esse não é realmente o caso.arr
está apontando paraa[]
si mesmo e, portanto, a leitura*arr
lerá e interpretará mal os primeiros 4 bytes (em uma compilação de 32 bits) ou 8 bytes (em uma compilação de 64 bits) comoa[]
sendo o valor de um ponteiro, o que não é. Então a desreferenciação desse ponteiro falha.Não use typecasts cegamente apenas para silenciar erros do compilador. Eles são erros por um motivo. Typecasts são úteis em certos casos, mas este não é um deles. A maneira correta
f1()
de chamara[]
no seu exemplo é assim:Alternativamente, mude
f1()
para aceitar um ponteiro para array em vez de um ponteiro para ponteiro:Quanto ao motivo pelo qual a chamada
f2(a)
funciona como está, é porque um array decai em um ponteiro para seu primeiro elemento ef2()
está usando esse ponteiro corretamente. Esse não é o caso quando você está ligandof1(&a)
.