Strings (linguagem C)

39 respostas
C
char *str1 = "bla";
char *str2 = "bla";

printf("%d", str1 == str2);

pq dá 1? como pode se tratar do mesmo endereço?
Explicações, por favor. :slight_smile:

39 Respostas

getAdicted

Posso estar falando besteira,

mas quando você faz *variavel, você está se referindo ao valor daquela posição de memória, portanto:

char *str1 = "bla";  
char *str2 = "bla";  
  
printf("%d", str1 == str2);

Retorna verdadeiro, dessa forma, imprimirá 1, por que *str1 == *str2, agora se quiser fazer referencia a posição de memória, deveria ser &variavel, não é isso?

[]'s

getAdicted

Estou no Windows, sem DevC++ :twisted:, não tenho como testar…

Poderia ser testado assim:

printf("%s",*str1)
printf("%s",*str2);

… os dois devem imprimir: “bla”, senão, falei besteira

falou!

diegohsi

Não sei bem em C, mas pesquisei aqui e entendi o seguinte…

0 = true
1 = false

entao como temos 2 variáveis e ponteiros para posições diferentes de memória retornará 1.

strcmp(str1, str2) é um função responsavel pela comparação retornando 0 são iguais, caso contrário são diferentes

getAdicted

1 = true
0 = false

não é diegohsi ?

verdadeiro e falso? :smiley:

[]'s

diegohsi

não

getAdicted

caracas! hehe

C

Posso estar falando besteira,

mas quando você faz *variavel, você está se referindo ao valor daquela posição de memória…

Quando faço:

char *str1 = "bla"; char *str2 = "bla";

Estou declarando e inicializando dois ponteiros para char.

Perdão, mas do jeito que eu entendi, isso não faz muito sentido.
Veja bem, na minha pergunta eu estou comparando dois ponteiros para char.
Se o código fosse:

Estaríamos comparando os char’s em si, o que também resultaria em 1, já que *str1 = *str2 = ‘b’.

printf("%s",*str1) printf("%s",*str2);

Perdão novamente, mas isso nem sequer deve compilar…
Como dito antes, *str1 e *str2 são char’s, não cadeias de char’s.

getAdicted

imprimir verdadeiro, 1:

#include<stdio.h>
int main(){
    char *str1 = "b";  
    char *str2 = "b";  
    printf("%c\n%c",*str1,*str2);
    printf("%d", str1 == str2);
    system("pause");
    return 0;
}

imprimir falso, 0:

#include<stdio.h>
int main(){
    char *str1 = "c";  
    char *str2 = "b";  
    printf("%c\n%c",*str1,*str2);
    printf("%d", str1 == str2);
    system("pause");
    return 0;
}

Não sei se no java verdadeiro é falso, hehe

Mas aqui deu certo.

getAdicted

Exato, por isso peguei só o primeiro caracter! Caso contrario deveria-se declarar um vetor de caracteres!

C

Não sei bem em C, mas pesquisei aqui e entendi o seguinte…

0 = true
1 = false

O amigo está enganado.

1 = true
0 = false

No caso, temos dois ponteiros para posições iguais, creio.
É exatamente aí que está a minha dúvida: como posso ter declarado e inicializado duas cadeias diferentes e elas apontarem pro mesmo lugar só por terem conteúdos iguais?

strcmp é uma função que compara conteúdos de duas cadeias, que não é o caso aqui, onde estamos comparando ponteiros.

getAdicted

boa…

getAdicted

Esse é do mestre!

Coordenador das olimpiadas de programação de Santos.

Sr. Ciro Cirne Trindade.

[]'s

C

Citando e comentando o código do amigo:

#include<stdio.h> int main(){ char *str1 = "b"; char *str2 = "b"; printf("%c\n%c",*str1,*str2); // aqui ele compara os dois conteúdos, logo é natural imprimir 1, o que não tem absoulutamente nada a ver com a minha pergunta hehe printf("%d", str1 == str2); // aqui ele compara os ponteiros, [b]perceba[/b], aqui está minha dúvida, vc declarou e inicializou duas cadeias de caracteres diferentes de conteúdos iguais, mas mesmo assim o programa retorna 1, mostrando que str1 e str2 ocupam posições de memória iguas. Como pode? =] system("pause"); return 0; }

getAdicted

Entendi, hehe

Mas é seis por meia duzia: str == *str, é isso?

getAdicted

Posições iguais no espaço? hehe

Não é contra a lei de um malandro ai?

kkkk

C

getAdicted:
Entendi, hehe

Mas é seis por meia duzia: str == *str, é isso?

Não… Veja bem, str se refere a um ponteiro, uma posição de memória.

Enquanto *str se refere ao conteúdo referenciado por esse ponteiro, no caso do código supracitado, um char.

str e *str são duas coisas diferentes no nosso código.

C

Exatamente o que o programa dá a entender…
E a razão desse tópico.
Saber pq str1 e str2 tratam do mesma posiçõa de memória. :wink:

getAdicted

Mesmo valor, posições de memória diferentes.


getAdicted

Valeu! Valeu!

bacana isso!

C

Poste o código, sem ele fica difícil analisar. :wink:

getAdicted
#include&lt;stdio.h&gt;
int main(){
    char *str1 = "b";  
    char *str2 = "b";  
    printf("%c\n%c\n\n\n",*str1,*str2);
    printf("%d, %d\n", &str1, &str2);
    system("pause");
    return 0;
}
C

Citando e comentando seu código:

#include<stdio.h> int main(){ char *str1 = "b"; char *str2 = "b"; printf("%c\n%c\n\n\n",*str1,*str2); // aqui está você imprimindo dois caracteres iguais. OK printf("%d, %d\n", &str1, &str2); // aqui está você imprimindo dois endereços DE ponteiros... O que novamente não tem absolutamente nada a ver com minha pergunta hehe system("pause"); return 0; }

str1 e str2 já são ponteiros em si. Teste com elas sem o & comercial e compare o resultado. :wink:

getAdicted

2 operadores unários são usados:

----- &: obtém o endereço de memória de uma variável
----- *: obtém o conteúdo do endereço de memória armazenado em um ponteiro

getAdicted

Agora eu entendi, hehe, prometo trazer a resposta, se não aparecer antes

[]'s

C

getAdicted:
2 operadores unários são usados:

----- &: obtém o endereço de memória de uma variável
----- *: obtém o conteúdo do endereço de memória armazenado em um ponteiro

Veja bem, amigo. Não confunda as coisas.
Eu jamais neguei isso.

Mas str1 e str2 já tratam de endereços, compreende?
Se não fossem, nem faria sentido vc usar *str1 ou *str2.

Agora, quando você usa &str1 ou &str1, vc obtém o endereço de memória de OUTRO endereço de memória, não percebe?

No tópico em questão estamos comparandos os endereços str1 e str2, não o edereços dos endereços . hehe

getAdicted

Se tratam sobre endereços tenho lá minhas dúvidas, mas será que eles tratam sobre posição? Talvez eles possam assumir tamanhos parecidos na memória, exemplo: *str1=1082144 até 1082148 == *str2 = 1082144 até 1082148. Sinceramente não sei como funciona.

… é pegadinha veia essa hein mano, hehe

C

Se tratam sobre endereços tenho lá minhas dúvidas, mas será que eles tratam sobre posição, talvez eles possam assumir tamanhos parecidos na memória, exemplo: *str1=1082144 até 1082148 == *str2 = 1082144 até 1082148. Sinceramente não sei como funciona.

str1 e str2 referenciam a mesma posição de memória.
A questão é: COMO PODE?

getAdicted

é coisa do demonio!

getAdicted

ai cake, ce tem parte com o capeta rapa… kkkk

brincadeira…

ViniGodoy

O motivo é exatamente o mesmo do Java.

Existe um pool de strings literais, que fica gravado na área de dados do processo. Portanto, duas literais com o mesmo valor (ou seja, strings criadas com aspas) irão ocupar o mesmo endereço de memória, pois o compilador irá reaproveita-las desse pool.

char* um = "valor"; char* dois = "valor";

O endereço de um e dois será o mesmo.

Para alterar essa situação, você deve criar os chars como arrays:

char[6] um = "valor"; char[] dois = "valor";

Pois aí o C garantirá a reserva do vetor de char e sua cópia. É também o motivo pelo qual após fazer:

char* teste = "Vanicius"; teste[1] = 'i';

Você pode dar pau, já que o seguimento de memória do buffer de strings é read-only.

ViniGodoy

Para mais informações, veja o item 6.4.5 do standard:
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n897.pdf

[i]"String literals are not required to be modifiable. This specification allows implementations to share copies of strings with identical text, to place string literals in read-only memory, and to perform certain optimizations. However, string literals do not have the type array of const char in order to avoid the problems of pointer type checking, particularly with library functions, since assigning a pointer to const char to a plain pointer to char is not valid. Those members of the C89 Committee
who insisted that string literals should be modifiable were content to have this practice designated a common extension (see §K.5.5).

Existing code which modifies string literals can be made strictly conforming by replacing the string
literal with an initialized static character array."[/i]

Esse tópico faz engenharia reversa para comparar as duas abordagens:

C

Ce manja mto, Vini!
Quando crescer quero ser q nem vc! =p

Brigadão!

ViniGodoy

cake:
Ce manja mto, Vini!
Quando crescer quero ser q nem vc! =p

E eu que nem o Thingol e o Entanglement…

getAdicted

Muito bem colocado Vinicius, eu consegui essa informação hoje pela manhã, eu ia postar, mas como você já o fez, meus trabalhos não serão mais necessários.

Se eu postar uma dúvida aqui, você poderia fazer a gentileza de olhar?

http://www.guj.com.br/posts/list/224200.java

Gostaria de um exemplo que utiliza essa modalidade de arquitetura.

Obrigado!

[]'s

C

Bom… Foi esclarecido que o C armazena as strings literais em um pool read only.

Então, estive pensando…
Ao declarar:

“esquilo” ocupará o pool para sempre?
Não há um coletor para apagá-lo caso eu anule e, há?

ViniGodoy

Sim.

Não, não existe. Garbage collection é coisa do java, heheheeh.

Agora, note que o standard permite que a implementação ou não de um pool fique a cargo do fabricante do compilador. Provavelmente compiladores para dispositivos mais humildes não terão esse recurso ou, no mínimo, terá uma flag para tornar isso opcional.

E note também que isso só vale para literais, que geralmente ocupam pouco espaço mesmo.

E

Dependendo do compilador (e até das opções de compilação), o lugar onde são guardadas strings literais pode estar em um segmento de memória apenas de leitura ou então que pode ser lido e escrito.

No caso do Microsoft Visual C++, a opção /GF (“enable read-only string pooling”) controla isso.

No caso do gcc, por causa de um recurso muito interessante (ele verifica se é possível combinar constantes strings, e se puder fazer isso, as combina), ele sempre tenta pôr em um pool read-only, já que senão você teria problemas mais graves que no Visual C++ (onde você, em tese, só estragaria uma constante, não um monte como poderia ser o caso do gcc).

Pelo que está escrito (não tenho um gcc aqui para confirmar), se você tivesse as seguintes strings:

char *nome1 = “Oliveira”;

char *nome2 = “Aparecido de Oliveira”;

char *nome3 = “José Aparecido de Oliveira”;

o gcc poderia guardar espaço apenas para “José Aparecido de Oliveira”, e fazer nome2 apontar para a posição dessa string que contém “Aparecido de Oliveira”, e nome3 apontar para “Oliveira”.
Então, se você mudasse a letra "v’ em nome1 para ‘b’, você teria nome1 = “Olibeira”, nome2 = “Aparecido de Olibeira”, e nome3 = “José Aparecido de Olibeira”. Obviamente isso é uma fonte infindável de bugs, portanto ele deve é deixar a string em um segmento read-only; nesse caso, o programa iria tomar uma exceção (ou um SIGBUS) quando fosse tentar mudar a letra ‘v’.

ViniGodoy

Ouvi dizer que alguns compiladores tem otimizações na std::string para se aproveitar de pools como esse. E no caso da std::string é ainda mais eficiente, já que ela não termina em \0. Então, no caso acima, a String “José” também compartilharia a área de José Aparecido de Oliveira.

Agora, não me recordo de cabeça se isso foi só um autor comentando da possibilidade, ou se tem algum compilador comercial implementado com o recurso.

G

Esse esquema de pool de strings é bem interessante.

Criado 11 de novembro de 2010
Ultima resposta 15 de nov. de 2010
Respostas 39
Participantes 6