limpando uma matriz char c

104

Achei que definir o primeiro elemento como nulo limparia todo o conteúdo de uma matriz char.

char my_custom_data[40] = "Hello!";
my_custom_data[0] = '\0';

No entanto, isso apenas define o primeiro elemento como nulo.

ou

my_custom_data[0] = 0; 

em vez de usar memset, pensei que os 2 exemplos acima deveriam limpar todos os dados.

ant2009
fonte
1
Jared, por que você definiu a tag c ++? ele falou sobre "C" e não adicionou nenhuma tag relacionada a C ++.
Johannes Schaub - litb
1
Isso se aplica igualmente bem a matrizes de caracteres em C ++, embora ele não tenha especificado.
Adam Hawes,
4
Removi a tag C ++ para evitar o que já vimos com pessoas que oferecem soluções específicas de C ++
Alnitak

Respostas:

113

Depende de como você deseja visualizar a matriz. Se você estiver vendo o array como uma série de caracteres, a única maneira de limpar os dados é tocar em cada entrada. memseté provavelmente a maneira mais eficaz de conseguir isso.

Por outro lado, se você estiver escolhendo ver isso como uma string C / C ++ terminada em nulo, definir o primeiro byte como 0 limpará efetivamente a string.

JaredPar
fonte
4
A palavra-chave na resposta é 'efetivamente'. Apenas o primeiro elemento é definido como 0 e o resto ainda tem valores indefinidos, mas se você estiver tratando a matriz como uma string terminada em nulo e o primeiro elemento for nulo, a string será considerada vazia.
Arnold Spence,
na verdade, esta é a resposta, pessoal.
Johannes Schaub - litb
@caparcode, exatamente. É por isso que é muito importante entender como o array está sendo usado.
JaredPar
Sim, isso é o que eu deveria ter dito no meu primeiro post. O char é uma string terminada. então qualquer um deles fará esse truque. char [0] = '\ 0'; ou char [0] = 0. Não tenho certeza, mas ouvi dizer que usar '\ 0' é melhor para usar strings com terminação nula.
ant2009
@robUK, sim, você está correto. Tecnicamente, '\ 0' é igual a 0 (em ascii), mas você deve usar '\ 0' porque torna sua intenção clara
Mark Testa
70

Um array em C é apenas um local de memória, então, de fato, sua my_custom_data[0] = '\0';atribuição simplesmente define o primeiro elemento como zero e deixa os outros elementos intactos.

Se você quiser limpar todos os elementos do array, terá que visitar cada elemento. É memsetpara isso:

memset(&arr[0], 0, sizeof(arr));

Geralmente, essa é a maneira mais rápida de cuidar disso. Se você pode usar C ++, considere std :: fill em vez disso:

char *begin = &arr;
char *end = begin + sizeof(arr);
std::fill(begin, end, 0);
John Feminella
fonte
1
Eu acredito que a segunda versão deveria ser: std :: fill (arr, arr + sizeof (arr) / sizeof (arr [0]), 0);
David Rodríguez - dribeas
Esclarecimento: não use sizeof com fill porque você terá problemas mais tarde com arrays de int, long, double ou o que for.
Zan Lynx
Eu prefiro: std :: fill (& arr [0], & arr [arr_len], 0);
Zan Lynx
Zan Lynx, esse é um comportamento indefinido. você não pode fazer & arr [arr_len]. mas você tem que fazer std :: fill (arr, arr + sizeof arr, 0); ou se você tiver o comprimento em algum lugar std :: fill (arr, arr + arr_len, 0); assumindo uma matriz de char
Johannes Schaub - litb
É válido apenas em C. embora a questão claramente visasse C (outro cara adicionou uma tag C ++, não tenho ideia do porquê), o std :: fill mostra afinidade C ++ :)
Johannes Schaub - litb
25

Por que você acha que definir um único elemento limparia todo o array? Em C, especialmente, pouco acontece sem o programador programá-lo explicitamente. Se você definir o primeiro elemento como zero (ou qualquer valor), terá feito exatamente isso e nada mais.

Ao inicializar, você pode definir uma matriz para zero:

char mcd[40] = {0}; /* sets the whole array */

Caso contrário, não conheço nenhuma técnica diferente de memset ou algo semelhante.

Abelenky
fonte
Acho que isso depende do compilador que você usa
cocoafan
1
@cocoafan: Não, não é dependente do compilador. Faz parte da especificação do idioma. Qualquer compilador que se comporta de maneira diferente não segue a linguagem C.
Abelenky
Eu não sabia disso, obrigado. Não consegui encontrar nenhum recurso onde possa ler este caso especial. Seria bom tê-lo como marcador.
cocoafan
1
É chamado de inicialização parcial. Eu não tenho a especificação C99, mas aqui estão duas fontes: bit.ly/enBC2m "Você não precisa inicializar todos os elementos em uma matriz. Se uma matriz for parcialmente inicializada, os elementos que não foram inicializados recebem o valor 0 de o tipo apropriado. " bit.ly/f9asHH "Se houver menos inicializadores do que elementos na matriz, os elementos restantes são inicializados automaticamente para 0"
abelenky
Isso não se aplica a uma matriz que já foi declarada e com valores atribuídos, certo?
skinnedKnuckles
10

Usar:

memset(my_custom_data, 0, sizeof(my_custom_data));

Ou:

memset(my_custom_data, 0, strlen(my_custom_data));
Jake1164
fonte
1
A segunda opção ( memset(my_custom_data, 0, strlen(my_custom_data));) limpará apenas o primeiro '\ 0', que pode estar além do final da matriz. Isso pode, ou não, estar bem.
brewmanz
9

Experimente o seguinte código:

void clean(char *var) {
    int i = 0;
    while(var[i] != '\0') {
        var[i] = '\0';
        i++;
    }
}
Cristian Altamirano
fonte
2
FYI - recue o código em 4 espaços ou selecione-o e aperte o botão 'código', que se parece com duas linhas de binário.
meagar
Excelente solução se você não quiser incluir string.h para memset ().
Akash Agarwal
7

Por que não usar memset()? É assim que se faz.

Definir o primeiro elemento deixa o resto da memória intocado, mas as funções str tratarão os dados como vazios.

John Fricker
fonte
1
Não use o conjunto memset sobre a legibilidade: stackoverflow.com/questions/453432/…
Johann Gerell
1
e qual é a sua resposta então?
mkb
6

Por favor, encontre abaixo onde eu expliquei os dados na matriz após os casos 1 e 2.

char sc_ArrData[ 100 ];
strcpy(sc_ArrData,"Hai" );

Caso 1:

sc_ArrData[0] = '\0';

Resultado:

-   "sc_ArrData"
[0] 0 ''
[1] 97 'a'
[2] 105 'i'
[3] 0 ''

Caso 2:

memset(&sc_ArrData[0], 0, sizeof(sc_ArrData));

Resultado:

-   "sc_ArrData"
[0] 0 ''
[1] 0 ''
[2] 0 ''
[3] 0 ''

Embora definir o primeiro argumento como NULL resolva o problema, é aconselhável usar o memset

Akaanthan Ccoder
fonte
4

Não. Tudo o que você está fazendo é definir o primeiro valor como '\ 0' ou 0.

Se você estiver trabalhando com strings terminadas em null, então, no primeiro exemplo, você obterá um comportamento que imita o que você espera, no entanto, a memória ainda está configurada.

Se você quiser limpar a memória sem usar o memset, use um loop for.

Alan
fonte
Eu digo não no loop for. Tente não escrever suas próprias funções de biblioteca "aprimoradas" (e geralmente não). Na verdade, memset e memcpy são bastante especiais e muitas vezes embutidos no código de máquina personalizado para a CPU com base no que é conhecido sobre o alinhamento e o comprimento dos dados.
Zan Lynx
@Zan o OP não deseja usar o memset (talvez ele esteja incorporado e não o tenha disponível). Mas sim, o memset geralmente é altamente ideal e provavelmente mais rápido do que um loop for.
Adam Hawes,
É verdade, entretanto, ele não queria usar o memset, então sugeri um loop for.
Alan
3

Você deve usar o memset. Definir apenas o primeiro elemento não funcionará, você precisa definir todos os elementos - se não, como você poderia definir apenas o primeiro elemento como 0?

Michael
fonte
O memset não deve ser usado sobre a legibilidade: stackoverflow.com/questions/453432/…
Johann Gerell
2

Escrever um caractere nulo para o primeiro caractere faz exatamente isso. Se você tratá-lo como uma string, o código que obedece ao caractere de terminação nulo o tratará como uma string nula, mas isso não é o mesmo que limpar os dados. Se você quiser realmente limpar os dados, precisará usar o memset.

Tvanfosson
fonte
2

Eu normalmente só faço assim:

memset(bufferar, '\0', sizeof(bufferar));
Jevgenij Kononov
fonte
1

Achei que definir o primeiro elemento como nulo limparia todo o conteúdo de uma matriz char.

Isso não está correto como você descobriu

No entanto, isso apenas define o primeiro elemento como nulo.

Exatamente!

Você precisa usar o memset para limpar todos os dados, não é suficiente definir uma das entradas como nula.

No entanto, se definir um elemento da matriz como nulo significa algo especial (por exemplo, ao usar uma string de terminação nula em), pode ser suficiente definir o primeiro elemento como nulo. Dessa forma, qualquer usuário do array entenderá que ele está vazio mesmo que o array ainda inclua os chars antigos na memória

Hhafez
fonte
Não use "memset" em vez de legibilidade: stackoverflow.com/questions/453432/…
Johann Gerell
1

defina o primeiro elemento como NULL. imprimir o array char não lhe dará nada em troca.


fonte
1

Que tal o seguinte:

bzero(my_custom_data,40);
codeconnundrum
fonte
-3
void clearArray (char *input[]){
    *input = ' '; 
}
Lobo
fonte
1
Isso não é CLARO, é apenas definir o primeiro caractere para ''! Acho que você queria escrever * input = '\ 0'
stviper
-4

Experimente o seguinte:

strcpy(my_custom_data,"");
Greg Grady
fonte