Logo Hardware.com.br
clicwar
clicwar Membro Junior Registrado
133 Mensagens 2 Curtidas

char a[] vs char *b

#1 Por clicwar 11/11/2006 - 18:44
As declarações: char a[]="ola mundo"; e char *b="ola mundo";
fazem o mesmo efeito a principio, mas porque é que na primeira da pra modifica o conteudo da string e na segunda nao da.

Ja pesquisei bastante sobre isso e encontrei as seguintes passagens:
"Typically, what happens is that the quoted string is stored in a data segment that is part of the executable file; when the program is loaded into memory, so is that string. The quoted string is said to be in static memory."
"In short, initializing the array copies a string from static storage to the array, whereas initializing the pointer merely copies the address of the string."

Agora vem as duvidas:

1) No primeiro o programa aloca espaço para o vetor e copia a string "ola mundo" para dentro do vetor (copia de onde??seria da tal pilha?) e no segundo o programa aloca espaço so para o ponteiro e faz esse ponteiro apontar para a string(seja la onde ela estiver). Seria isso mesmo que acontece???

2) Entao no segundo caso nao da pra modificar o conteudo da string porque ela esta numa regiao da memoria que nao é possivel mudar os valores OU é porque o ponteiro esta apontado para uma string armazenada no proprio arquivo .EXE (meio estranho isso) ???

Basicamente o que eu quero saber é:
Aonde é que fica a string antes de ser copiada para dentro do vetor no primeiro caso e aonde é que ela fica no segundo caso
E porque que somento o primeiro caso é modificavel.


P.S.:só mais uma coisa: ja que só o primeiro é modificavel nao é melhor usar sempre só a primeira forma?

Muito Obrigado.
The Doug
The Doug Super Participante Registrado
890 Mensagens 10 Curtidas
#2 Por The Doug
11/11/2006 - 19:31
Na discussão que se segue, todas as atribuições devem ser entendidas como sendo globais, ou seja, feitas fora de qualquer função, incluindo main().

Podemos escrever:

char my_string[40] = "Ted";

o que irá alocar espaço para um array de 40 bytes e colocar a string nos primeiros 4 bytes (três para os caracteres entre aspas e o quarto para guardar o terminador '\0').

Na verdade, se tudo o que quiséssemos era armazenar o nome "Ted" poderíamos ter escrito:

char my_name[] = "Ted";

e o compilador contaria os caracteres, deixaria espaço para o caracter nul e armazenar o todal de quatro caracteres na posição de memória que seria retornada pelo nome do array, neste caso, my_name;

Em alguns códigos, em vez do acima, você pode ver:

char *my_name = "Ted";

que é a abordagem alternativa. Existe uma diferença entre elas? A resposta é... sim. Usando a notação de array 4 bytes de armazenamento no bloco de memória estática é separado, um para cada caracter e um para o caracter nul terminador. Mas na notação de ponteiro os mesmos 4 bytes são requeridos, mais N bytes para armazenar a variável ponteiro my_name (onde N depende do sistema, mas usualmente é um mínimo de 2 bytes e pode ser 4 ou mais).

Na notação arary, my_name é uma abreviação para &my_name[0] que é o endereço do primeiro elemento do array. Como a localização do array é fixo durante o tempo de execução, esta é uma constante (e não uma variável). Na notação de ponteiro, my_name é uma variável. Sobre qual o melhor método, isto depende do que você vai fazer no resto do programa.

Avancemos um passo adiante e consideremos o que acontece se cada uma destas declarações é feita dentro de uma função em vez de ser feita globalmente, fora dos limites de qualquer função.


void my_function_A(char *ptr)
{
char a[] = "ABCDE"
.
.
}


void my_function_B(char *ptr)
{
char *cp = "FGHIJ"
.
.
}

No caso de my_function_A, o conteúdo, ou valor(es) do array a[] é considerado como sendo os dados. O array é dito como tendo inicialmente os valores ABCDE. NO caso de my_function_B o valor do ponteiro cp é considerado como sendo o dado. O ponteiro inicialmente aponta para a string FGHIJ. Tanto em my_function_A e my_function_B as definições são variáveis locais e assim a string ABCDE é armazenada na pilha, bem como é o valor do ponteiro cp. A string FGHIJ pode ser armazenada em qualquer lugar. Em meu sistema ela é armazenada no segmento de dados.

A propósito, a inicialização de variáveis automáticas de array como eu fiz em my_function_A seria ilegal no velho K&R C e somente "amadureceu" no mais recente ANSI C. Um fato que pode ser importante quando se considera portabilidade e compatibilidade retroativa.
Visitem meu site:

www.infotalkers.com
clicwar
clicwar Membro Junior Registrado
133 Mensagens 2 Curtidas
#3 Por clicwar
11/11/2006 - 21:35
E essa região: "segmento de dados" é a mesma região "data segment" da citação:"Typically, what happens is that the quoted string is stored in a data segment that is part of the executable file; when the program is loaded into memory, so is that string. The quoted string is said to be in static memory." ?

Esses dois textos me levam a a concluir que:
Então a string está de fato no arquivo executavel e só sai de lá para a pilha quando for copiada para dentro de um vetor, o que nao ocorre no segundo caso(caso do ponteiro char *b), mas ocorre no primeiro(caso do char a[]), e é por isso que só no primeiro caso é possivel modifica-la.
No segundo caso o programa não pode alterar o arquivo executavel, mas tem um ponteiro apontando para ele(essa parte ta meio dificil de engolir, um ponteiro para o arquivo executavel??).

Foi uma conclusão feliz??? Caso contrario apontem erros nela.

Muito Obrigado pela contribuição, The Doug.
Canal nao-oficial do forum (iniciativa de usuarios para usuarios)
irc.freenode.net canal #fgdh
jackinabox
jackinabox Veterano Registrado
1.1K Mensagens 8 Curtidas
#4 Por jackinabox
11/11/2006 - 23:01
Artigo original do texto que o The Doug traduziu:
http://pw1.netcom.com/~tjensen/ptr/ch6x.htm

clicwar disse:
As declarações: char a[]="ola mundo"; e char *b="ola mundo"; fazem o mesmo efeito a principio

Não fazem o mesmo efeito.

Considerando que em ambos os casos estamos declarando variáveis locais:

O primeiro caso (char []) declara e inicializa um array cujo tamanho será automaticamente determinado pelo compilador. Essa inicialização corresponde ao "preenchimento" de todos os elementos do array, incluindo o caracter terminador '\0'.

O segundo caso (char *) declara e inicializa um ponteiro para uma string, que será tipicamente armazenada como um "array anônimo" em uma área de memória read only. Essa inicialização corresponde a atribuir para a variável o endereço de memória onde a string foi armazenada.


1) No primeiro o programa aloca espaço para o vetor e copia a string "ola mundo" para dentro do vetor (copia de onde?? seria da tal pilha?)

Bem, nos dois casos, você escreveu no seu código fonte uma string literal (aquilo que está lá entre aspas). O compilador, ao gerar o código objeto, irá determinar onde essas strings literais serão armazenadas (no segmento de dados, por exemplo). Então é desse lugar que o compilador irá, no caso do char [], copiar os caracteres para dentro do array.

O array ficará na pilha, mas os caracteres que foram utilizados para inicializar o array foram copiados a partir de outro lugar (segmento de dados).


2) Entao no segundo caso nao da pra modificar o conteudo da string porque ela esta numa regiao da memoria que nao é possivel mudar os valores

Sim. E é assim por definição.


P.S.:só mais uma coisa: ja que só o primeiro é modificavel nao é melhor usar sempre só a primeira forma?

Bem, cada caso é um caso. De qualquer forma, se você quiser modificar a string armazenada em um array, precisará prestar atenção ao tamanho máximo do array, né? Ou seja, se você inicializá-lo automaticamente assim: char a[] = "abc"; então o array poderá ter, no máximo, 3 caracteres, certo? E se você precisar mais tarde armazenar, digamos, até 35 caracteres aí nesse array? Ora, então você deveria ter inicializado , por exemplo, assim: char a[36] = "abc";
Jeferson Charles Mayer

"Como é que eu vou enxergar a tal floresta, com todas essas árvores atrapalhando a visão?"
jackinabox
jackinabox Veterano Registrado
1.1K Mensagens 8 Curtidas
#5 Por jackinabox
11/11/2006 - 23:10
clicwar disse:
E essa região: "segmento de dados" é a mesma região "data segment" da citação:...

Sim.


Então a string está de fato no arquivo executavel e só sai de lá para a pilha quando for copiada para dentro de um vetor

Não. Não existe essa história de "só sair do executável depois".
Lembre-se do seguinte: você digitou, no seu código fonte, uma string literal (algo como "abc"). Então, obviamente, essa string está contida dentro do executável. Mas isso não significa que a string será lida a partir do executável somente no momento da inicialização do array! Essa string é carregada para um segmento específico de memória quando seu programa for inicialmente carregado na memória para rodar. E no caso de o array ser uma variável local, a string será copiada para o array quando a função correspondente for executada.


No segundo caso o programa não pode alterar o arquivo executavel, mas tem um ponteiro apontando para ele(essa parte ta meio dificil de engolir, um ponteiro para o arquivo executavel??).

Certamente que não. Ponteiros somente apontam para posições de memória.
Jeferson Charles Mayer

"Como é que eu vou enxergar a tal floresta, com todas essas árvores atrapalhando a visão?"
© 1999-2024 Hardware.com.br. Todos os direitos reservados.
Imagem do Modal