
		paulo1205
		
		(usa Ubuntu)
		
		Enviado em 21/11/2021 - 15:54h 
		ApprenticeX escreveu:
Boa Noite a Todos,
Como apagar um vetor/array corretamente!
Entendi que vetor e array é a mesma coisa! Está certo isso? 
No contexto de programação em C, 
array e vetor são frequentemente usados para referir-se ao mesmo tipo de objeto, que é a disposição de vários elementos em posições adjacentes de memória, podendo ser indexados a partir de um endereço de primeiro elemento e um deslocamento para algum elemento após o primeiro.  A tradução direta de 
array seria “arranjo”, mas essa expressão não vingou muito no Brasil; “vetor” acabou sendo mais comum. Em Inglês, raramente vejo usarem 
vector (exceto em C++, que tem o tipo 
std::vector como um tipo de 
array dinamicamente alocado), e 
array me parece ser mais comum.
No exemplo abaixo estou tentando saber qual a melhor forma de apagar uma string, ou melhor dizendo um vetor de caracteres
 char Text[] = "Viva o Linux";
// Considerei assim a melhor, é isso mesmo? Pois aqui não uso nenhuma função apenas 1 Operador!
for(int x = 0; x < sizeof(Text); x++) Text[x] = 0; 
  
Não esqueça de considerar o laço de repetição. Na prática, é a mesma coisa que 
memset() faz por dentro.
 /* Qual dos memset abaixo de fato é o correto? Porque fiquei confuso com tantas formas!
   1) Uso Text OU &Text ???
   2) Uso sizeof Text OU sizeof(Text)
   3) Uso 0x0 OU 0 OU \0
   3) O que é esse 0x0 ??? Ele é melhor?
*/ 
  
Dado que o primeiro parâmetro de 
memset() é do tipo “ponteiro para qualquer tipo de dados” (
void *) e que o segundo parâmetro é do tipo 
int, todas as formas são sintaticamente corretas.
Falando do segundo parâmetro primeiro, o fato de você ter um protótipo de função que obriga que o valor do parâmetro seja do tipo 
int já basta para que você não tenha muito como fugir de que o valor passado à função será um valor inteiro, mesmo que ele tenha de ser convertido implicitamente pelo compilador.
Note porém que todas as constantes que você usou têm o mesmo valor e o mesmo tipo, sendo apenas representações diferentes da mesma coisa: 
0 é um valor inteiro com valor igual a zero, expresso numa notação correspondente a uma constante decimal; 
0x0 é o mesmo valor zero em notação hexadecimal, 
00 (que você não usou, mas que eu tomei a liberdade de incluir aqui) é o mesmo valor inteiro zero, mas em notação octal; e 
'\0' também é um valor inteiro em C
† e também vale zero, igual a todos os outros exemplos nesta lista.
Quanto ao primeiro argumento, lembre-se que o tipo de 
Text, de acordo com a declaração, é “
array com 13 elementos do tipo 
char” (12 do texto, mais o terminador). Entretanto, quando o nome de um 
array é usado em expressões que não envolvem a aplicação direta de 
sizeof ou de 
& sobre si, o valor produzido é do tipo “ponteiro para 
char”, indicando o endereço do primeiro elemento.
Por outro lado, quando você tem a aplicação de 
sizeof ou 
& ao nome do 
array, ele não decai para ponteiro, mas continua um 
array. Desse modo, 
sizeof Text produz um valor do tipo 
size_t correspondente ao tamanho total, medido em 
bytes, ocupado na memória por todos os elementos do 
array — como os elementos de 
Text são do tipo 
char, que, por definição, ocupam um 
byte cada, o tamanho do 
array é igual ao número de seus elementos elementos, que é 13.
Por sua vez, 
&Text produz um valor do tipo “ponteiro para 
array com 13 elementos do tipo 
char”, correspondente ao endereço inicial do bloco de memória onde o 
array está disposto. Devido à forma como o C prescreve a disposição de dados na memória, o endereço inicial do 
array é numericamente equivalente ao endereço ocupado por seu primeiro elemento. Em C, essa equivalência pode aparecer com o valor verdadeiro retornado pelas comparações 
(void *)Text==(void *)&Text, ou 
(intptr_t)Text==(intptr_t)&Text (
intptr_t, definido em <stdint.h>, é um tipo de valor inteiro que seja suficiente para converter um ponteiro; nos nossos PCs de 64 bits, ele provavelmente corresponde a 
unsigned long long); entretanto, a comparação 
Text==&Text é errônea, pois não é válido comparar diretamente ponteiros para dados de tipos diferentes, e o próprio compilador vai alarmar.
Para uso com 
memeset(), no entanto, as duas formas acabam não fazendo muita diferença, já que o tipo do primeiro parâmetro é 
void *, ou um “ponteiro para qualquer tipo de dados”. A implementação interna de 
memset() é funcionalmente equivalente ao seguinte código (deliberadamente não-otimizado, para ser didático).
 void *memset(void *s, int c, size_t size){
  unsigned char *cp=s;  // Em C, pode-se converter void * em qualquer outro tipo de ponteiro automaticamente (em C++, isso seria um erro).
  const unsigned char ch=c;  // Valor a ser atribuído a cada byte na memória.
  while(size--)
    *cp++=ch;
  return s;
} 
O que se pode dizer sobre a diferença entre 
memset(Text, 0, sizeof Text) e 
memset(&Text, 0, sizeof Text) é que, no primeiro caso, o programador provavelmente tem em mente a atribuição de um valor nulo a cada um dos elementos do 
array, ao passo que o segundo dá a ideia de que o programador não está preocupado com cada elemento do 
array, mas apenas com que todos o bloco de memória seja preenchido com 
bytes nulos.
Conhecendo a implementação interna da função, sabemos bem que o resultado é o mesmo, e a diferença acaba ficando mais no campo semântico-filosófico. É acaba sendo meio irônico que 
memset() esteja em <string.h>, juntamente com outras funções que trabalham com 
arrays de caracteres contendo uma representação específica de 
strings, em vez de, talvez, <stdlib.h>, onde estão algumas funções que lidam com dados mais genéricos, tais como 
bsearch() e 
qsort() (mas, por outro lado, há em <stdlib.h> coisas que eu, particularmente, acho que ficariam mais devidamente colocadas em <string.h>, tais como as funções de conversão de 
strings em valores numéricos, tais como 
strtol(), 
strtod() e outras da mesma família).
Com relação ao uso do operador 
sizeof, seu operando não precisa estar entre parênteses se for uma expressão sintaticamente válida sem parênteses. Assim sendo, quando o operando é o nome de um símbolo (i.e. nome de uma variável, 
array, função ou constante de uma enumeração), uma constante ou uma expressão que produz um 
lvalue sem necessitar de parênteses, a forma canônica de fazer é escrever é “
sizeof X”. Com operandos desses tipos, o uso de parênteses é redundante, e portanto deveria ser evitado, a não ser em casos em que fossem muito convenientes para melhorar a clareza (embora não me ocorra nenhum exemplo no momento), e seria melhor que isso fosse feito na forma “
sizeof (X)”, com um espaço entre o operador e o operando, destacando que os parênteses não fazem parte da sintaxe do operando em si.
Note que eu não incluí nos casos acima nomes de tipos de dados, tais como 
char, 
int * ou 
struct tm. Ao usar 
sizeof com nomes de tipos, em lugar de com dados cujo tipo será determinado pelo compilador, você é obrigado a colocar o nome do tipo entre parênteses, sim. Mas tipicamente, isso é feito com a forma “
sizeof (T)”, com um espaço entre o operador e a abertura de parênteses.
----
† Esta é provavelmente a incompatibilidade mais básica entre o C e o C++, pois nesta última constantes literais entre apóstrofos são do tipo 
char, não do tipo 
int, como em C.
... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)