mais duvidas sobre ponteiros rs [RESOLVIDO]

1. mais duvidas sobre ponteiros rs [RESOLVIDO]

Daniel
danielcrvg

(usa Slackware)

Enviado em 01/01/2015 - 14:53h

Ola pessoal..

antes de mais nada feliz ano novo.

Eu to estudando baseado no livro do luis damas 10 ed + google.com sobre os ponteiros em C.

Pontos que eu acho que entendi:

- A memoria RAM é sequencial:

| 1 | 2 | 3 |....| 1000 | 1001 | 1002 | ... |até o fim..
Endereco 1, endereco 2.....

- O tipo da variavel serve para definir quantos blocos (bytes) de memoria um dado ira ocupar, ex:
int 2 ou 4 bytes (dependendo da arquitetura), float 4, char 1.. etc...


- Vetor de char vs String ..

As diferencas que eu entendi:

Strings sao definidas como char e os dados ficam entre " " e vetor de chars ' ', exemplo:

char nome[] = "daniel";

em quanto vetor de chars:

char nome[] = {'d','a'.'n','i','e','l'};

Nas strings, quando não se define o tamanho, o compilador automaticamente ja coloca o 'barra0' no final dela.


Bom agora vem minha duvida:


int main(){

char xxx[]="daniel";
int i = 0;
char *ptnome;
ptnome=&xxx;

printf("ENDENTENDO O BASICO SOBRE PONTEIROS\n");

printf("\n\n.:[ STRINGS ]:.\n");
printf("\nConteudo de 'xxx' (%%s, xxx): %s\n",xxx);
printf("Endereco de 'xxx' (%%p, &xxx): %p\n",&xxx);
ptnome=&xxx;
printf("Endereço de 'ptnome' (%%p, &ptnome): %p\n",&ptnome);
printf("Conteudo de 'ptnome (%%s, ptnome)': %s\n",ptnome);
printf("Endereço que 'ptnome' aponta (%%p, ptnome): %p\n\n",ptnome);

int zzz=10;
int *ptzzz;
printf("\n.:[ INTEIROS ]:.\n");
printf("\nConteudo de 'zzz' (%%d, zzz): %d\n",zzz);
printf("Endereco de 'zzz' (%%p, &zzz): %p\n",&zzz);

ptzzz=&zzz;
printf("Endereço de 'ptzzz' (%%p, &ptzzz): %p\n",&ptzzz);
printf("Conteudo de 'ptzzz' (%%d, *ptzzz): %d\n",*ptzzz);
printf("Endereço que 'ptzzz' aponta (%%p, ptzzz): %p\n",ptzzz);

printf("\n--------------------------------\n");
printf("Primeiro elemento de 'xxx': %c\n",xxx[0]);
printf("Endereco do 1 elemento: %p\n",&xxx[0]);
printf("Endereco do vetor: %p\n",&xxx);


printf("\nImprimindo elementos da string com ponteiros: \n");
for (i=0;i<strlen(xxx);i++) {
printf("%c : %p\n",*ptnome++,&ptnome[i]);
}
char nome2[6]={'d','a','n','i','e','l'};
char *ptnome2;
ptnome2=&nome2;
i = 0;

printf("\nImprimindo elementos do vetor de char com ponteiros: \n");
for (i=0;i<strlen(xxx);i++) {
printf("%c : %p\n",*ptnome2++,&ptnome2[i]);
}

printf("\nTamanho de um char: %d\n",sizeof(char));

return 0;
}


Na primeira parte eu apenas imprimi na tela valores, enderecos de memoria, etc apenas para manipular os ponteiros..

Ai quando eu resolvi imprimir o vetor de char que me bateu a duvida:

Se o char tem apenas 1 byte, pq o seu endereco de memoria esta sendo de 2 em 2, ao inves de ser de 1 em 1 ??

Tipo uma string mesmo com 1 caracter tem tamanho dois, por que é o caracter + o 'barra0' delimitador do tamanho certo?

Mas o tipo char nao é apenas 1 byte??




  


2. MELHOR RESPOSTA

Enzo de Brito Ferber
EnzoFerber

(usa FreeBSD)

Enviado em 01/01/2015 - 22:17h



int main(){

char xxx[]="daniel";
int i = 0;
char *ptnome;
ptnome=&xxx;

printf("ENDENTENDO O BASICO SOBRE PONTEIROS\n");

printf("\n\n.:[ STRINGS ]:.\n");
printf("\nConteudo de 'xxx' (%%s, xxx): %s\n",xxx);
printf("Endereco de 'xxx' (%%p, &xxx): %p\n",&xxx);
ptnome=&xxx;
printf("Endereço de 'ptnome' (%%p, &ptnome): %p\n",&ptnome);
printf("Conteudo de 'ptnome (%%s, ptnome)': %s\n",ptnome);
printf("Endereço que 'ptnome' aponta (%%p, ptnome): %p\n\n",ptnome);

int zzz=10;
int *ptzzz;
printf("\n.:[ INTEIROS ]:.\n");
printf("\nConteudo de 'zzz' (%%d, zzz): %d\n",zzz);
printf("Endereco de 'zzz' (%%p, &zzz): %p\n",&zzz);

ptzzz=&zzz;
printf("Endereço de 'ptzzz' (%%p, &ptzzz): %p\n",&ptzzz);
printf("Conteudo de 'ptzzz' (%%d, *ptzzz): %d\n",*ptzzz);
printf("Endereço que 'ptzzz' aponta (%%p, ptzzz): %p\n",ptzzz);

printf("\n--------------------------------\n");
printf("Primeiro elemento de 'xxx': %c\n",xxx[0]);
printf("Endereco do 1 elemento: %p\n",&xxx[0]);
printf("Endereco do vetor: %p\n",&xxx);


printf("\nImprimindo elementos da string com ponteiros: \n");
for (i=0;i<strlen(xxx);i++) {
printf("%c : %p : %d\n",ptnome[i],&ptnome[i],sizeof(ptnome[i]));
}
char nome2[6]={'d','a','n','i','e','l'};
char *ptnome2;
ptnome2=&nome2;
i = 0;

printf("\nImprimindo elementos do vetor de char com ponteiros: \n");
for (i=0;i<strlen(xxx);i++) {
printf("%c : %p : %d\n",ptnome2[i],&ptnome2[i],sizeof(ptnome2[i]));
}

return 0;
}



O meu output:


ENDENTENDO O BASICO SOBRE PONTEIROS


.:[ STRINGS ]:.

Conteudo de 'xxx' (%s, xxx): daniel
Endereco de 'xxx' (%p, &xxx): 0x7fff5c72fc15
Endereço de 'ptnome' (%p, &ptnome): 0x7fff5c72fc08
Conteudo de 'ptnome (%s, ptnome)': daniel
Endereço que 'ptnome' aponta (%p, ptnome): 0x7fff5c72fc15


.:[ INTEIROS ]:.

Conteudo de 'zzz' (%d, zzz): 10
Endereco de 'zzz' (%p, &zzz): 0x7fff5c72fc04
Endereço de 'ptzzz' (%p, &ptzzz): 0x7fff5c72fbf8
Conteudo de 'ptzzz' (%d, *ptzzz): 10
Endereço que 'ptzzz' aponta (%p, ptzzz): 0x7fff5c72fc04

--------------------------------
Primeiro elemento de 'xxx': d
Endereco do 1 elemento: 0x7fff5c72fc15
Endereco do vetor: 0x7fff5c72fc15

Imprimindo elementos da string com ponteiros:
d : 0x7fff5c72fc15 : 1
a : 0x7fff5c72fc16 : 1
n : 0x7fff5c72fc17 : 1
i : 0x7fff5c72fc18 : 1
e : 0x7fff5c72fc19 : 1
l : 0x7fff5c72fc1a : 1

Imprimindo elementos do vetor de char com ponteiros:
d : 0x7fff5c72fbf2 : 1
a : 0x7fff5c72fbf3 : 1
n : 0x7fff5c72fbf4 : 1
i : 0x7fff5c72fbf5 : 1
e : 0x7fff5c72fbf6 : 1
l : 0x7fff5c72fbf7 : 1


O ultimo código eu editei, esqueci de colocar o [ i ] na primeira referencia do ponteiro.

*

Ah, e não são apenas ponteiros para char que têm 8 bytes não. Todos os ponteiros em arquiteturas de 64bits tem 8 bytes.


[]'s

3. Re: mais duvidas sobre ponteiros rs [RESOLVIDO]

Enzo de Brito Ferber
EnzoFerber

(usa FreeBSD)

Enviado em 01/01/2015 - 20:06h

Feliz ano novo!

Então, um (char) é um tipo básico de dado, ele possui 1 byte. (0 a 255).

Já um (char *) é um ponteiro para char. Isso significa que o valor do ponteiro é um endereço de memória, e esse tamanho depende da arquitetura do sistema.


#include <stdio.h>

int main ( void ) {
char *s, c;

printf ( "Ponteiro char: %d\n", sizeof(s));

printf ( "Tipo char: %d\n", sizeof(c));

return 0;

}



No meu computador, que é 64 bits, o tamanho do ponteiro é 8 bytes, o tamanho do char é 1 byte.
O tamanho do tipo char não irá alterar, pois o padrão na linguagem C é 1 byte.

Já o ponteiro vai alterar de computador para computador: se seu computador for 16bits, o ponteiro será 2 bytes, se for 32bits será 4 bytes e se for 64bits será 8 bytes.


*

Como você disse, a memória é sequencial. Toda informação está na memória, então o ponteiro e o char estão na memória. A diferença é:

Numa arquitetura 64bits, TODOS os endereços de memória tem 8 bytes. Logo, se um ponteiro irá conter um endereço de memória, ele precisa ser de 8 bytes.



Memoria e seu endereço:
[ 0x0000000000000000 ][ 0x0000000000000001 ][ 0x0000000000000002 ][ 0x0000000000000003 ]

Um ponteiro precisa apontar para uma unidade de memória.

Então imagine um ponteiro que está no primeiro endereço de memória (0x0000000000000000) e aponta para o segundo elemento (0x0000000000000001). O segundo endereço de memória tem um char, assim:
O CONTEÚDO da memória vai ficar assim:

End: [ 0x0000000000000000 ][ 0x0000000000000001 ][ 0x0000000000000002 ][ 0x0000000000000003 ]
Val: [ 0x0000000000000001 ][ 'c' ][ ------lixo------ ][ ------lixo------ ]

Essa representação de memória acima poderia ser conseguida por um programa assim:

char *p;
char c;

p = &c;
printf("%p", &p ); // irá imprimir 0x0000000000000000
printf("%p", p ); // ira imprimir 0x0000000000000001
printf("%p", &c); // ira imprimir 0x0000000000000001



Deu pra entender?

Qualquer coisa posta denovo,
[]'s


4. Re: mais duvidas sobre ponteiros rs [RESOLVIDO]

Daniel
danielcrvg

(usa Slackware)

Enviado em 01/01/2015 - 20:26h

EnzoFerber escreveu:

Feliz ano novo!

Então, um (char) é um tipo básico de dado, ele possui 1 byte. (0 a 255).

Já um (char *) é um ponteiro para char. Isso significa que o valor do ponteiro é um endereço de memória, e esse tamanho depende da arquitetura do sistema.


#include <stdio.h>

int main ( void ) {
char *s, c;

printf ( "Ponteiro char: %d\n", sizeof(s));

printf ( "Tipo char: %d\n", sizeof(c));

return 0;

}



No meu computador, que é 64 bits, o tamanho do ponteiro é 8 bytes, o tamanho do char é 1 byte.
O tamanho do tipo char não irá alterar, pois o padrão na linguagem C é 1 byte.

Já o ponteiro vai alterar de computador para computador: se seu computador for 16bits, o ponteiro será 2 bytes, se for 32bits será 4 bytes e se for 64bits será 8 bytes.


*

Como você disse, a memória é sequencial. Toda informação está na memória, então o ponteiro e o char estão na memória. A diferença é:

Numa arquitetura 64bits, TODOS os endereços de memória tem 8 bytes. Logo, se um ponteiro irá conter um endereço de memória, ele precisa ser de 8 bytes.



Memoria e seu endereço:
[ 0x0000000000000000 ][ 0x0000000000000001 ][ 0x0000000000000002 ][ 0x0000000000000003 ]

Um ponteiro precisa apontar para uma unidade de memória.

Então imagine um ponteiro que está no primeiro endereço de memória (0x0000000000000000) e aponta para o segundo elemento (0x0000000000000001). O segundo endereço de memória tem um char, assim:
O CONTEÚDO da memória vai ficar assim:

End: [ 0x0000000000000000 ][ 0x0000000000000001 ][ 0x0000000000000002 ][ 0x0000000000000003 ]
Val: [ 0x0000000000000001 ][ 'c' ][ ------lixo------ ][ ------lixo------ ]

Essa representação de memória acima poderia ser conseguida por um programa assim:

char *p;
char c;

p = &c;
printf("%p", &p ); // irá imprimir 0x0000000000000000
printf("%p", p ); // ira imprimir 0x0000000000000001
printf("%p", &c); // ira imprimir 0x0000000000000001



Deu pra entender?

Qualquer coisa posta denovo,
[]'s



Opa...

obrigado pela informação... eu nao sabia que o ponteiro para um char tem o tamanh de de 8 bytes (64 bits)

mas de qualquer forma, eu so fiquei encucado pq meu vetor normal ta pulando os enderecos de memoria de 2 em 2 na hora que eu imprimo o endereco de memoria saca..

Exemplo:

'd' 'a' 'n' 'i' 'e' 'l' - Valor
-----------------------
0 | 1 | 2 | 3 | 4 | 5 | - Endereco

tipo cada letra iria ocupar 1 byte certo?

ai quando eu imprimo o endereco de memoria, deveria sair assim 0,1,2,3,4,5..

So que no meu codigo ele na hora de imprimir o endereco de memoria, "aparentemente" ele esta imprimindo o endereco de memoria, mas tipo o ultimo algarismo do endereco ta pulando de 2 em 2.. tipo end0 end2 end4 end6...

ai eu fiquei curioso..

mas é so curiosidade mesmo.. eu fico lendo e ja boto em pratica pra ve se o autor tem razao ou nao rsrs


5. Re: mais duvidas sobre ponteiros rs [RESOLVIDO]

Enzo de Brito Ferber
EnzoFerber

(usa FreeBSD)

Enviado em 01/01/2015 - 21:55h

Opa,

Tá dando esse bug por um erro no seu código:



for (i=0;i<strlen(xxx);i++) {
printf("%c : %p\n",*ptnome++,&ptnome[i]);
}



Troca por:


for (i=0;i<strlen(xxx);i++) {
printf("%c : %p\n",ptnome[i],&ptnome[i]);
}



Você tá incrementando o ponteiro, e depois imprimindo o endereço de i bytes a frente desse endereço.

Muda aí e me fala se deu.

[]'s



6. Re: mais duvidas sobre ponteiros rs [RESOLVIDO]

Daniel
danielcrvg

(usa Slackware)

Enviado em 01/01/2015 - 22:05h

EnzoFerber escreveu:

Opa,

Tá dando esse bug por um erro no seu código:



for (i=0;i<strlen(xxx);i++) {
printf("%c : %p\n",*ptnome++,&ptnome[i]);
}



Troca por:


for (i=0;i<strlen(xxx);i++) {
printf("%c : %p\n",ptnome[i],&ptnome[i]);
}



Você tá incrementando o ponteiro, e depois imprimindo o endereço de i bytes a frente desse endereço.

Muda aí e me fala se deu.

[]'s




rsrs aqui funciona.. se eu coloco do seu jeito ai que da bug kkk

perai vou atualizar aqui como ta:


int main(){

char xxx[]="daniel";
int i = 0;
char *ptnome;
ptnome=&xxx;

printf("ENDENTENDO O BASICO SOBRE PONTEIROS\n");

printf("\n\n.:[ STRINGS ]:.\n");
printf("\nConteudo de 'xxx' (%%s, xxx): %s\n",xxx);
printf("Endereco de 'xxx' (%%p, &xxx): %p\n",&xxx);
ptnome=&xxx;
printf("Endereço de 'ptnome' (%%p, &ptnome): %p\n",&ptnome);
printf("Conteudo de 'ptnome (%%s, ptnome)': %s\n",ptnome);
printf("Endereço que 'ptnome' aponta (%%p, ptnome): %p\n\n",ptnome);

int zzz=10;
int *ptzzz;
printf("\n.:[ INTEIROS ]:.\n");
printf("\nConteudo de 'zzz' (%%d, zzz): %d\n",zzz);
printf("Endereco de 'zzz' (%%p, &zzz): %p\n",&zzz);

ptzzz=&zzz;
printf("Endereço de 'ptzzz' (%%p, &ptzzz): %p\n",&ptzzz);
printf("Conteudo de 'ptzzz' (%%d, *ptzzz): %d\n",*ptzzz);
printf("Endereço que 'ptzzz' aponta (%%p, ptzzz): %p\n",ptzzz);

printf("\n--------------------------------\n");
printf("Primeiro elemento de 'xxx': %c\n",xxx[0]);
printf("Endereco do 1 elemento: %p\n",&xxx[0]);
printf("Endereco do vetor: %p\n",&xxx);


printf("\nImprimindo elementos da string com ponteiros: \n");
for (i=0;i<strlen(xxx);i++) {
printf("%c : %p : %d\n",*ptnome++,&ptnome[i],sizeof(ptnome[i]));
}
char nome2[6]={'d','a','n','i','e','l'};
char *ptnome2;
ptnome2=&nome2;
i = 0;

printf("\nImprimindo elementos do vetor de char com ponteiros: \n");
for (i=0;i<strlen(xxx);i++) {
printf("%c : %p : %d\n",*ptnome2++,&ptnome2[i],sizeof(ptnome2[i]));
}

return 0;
}



7. Re: mais duvidas sobre ponteiros rs [RESOLVIDO]

Enzo de Brito Ferber
EnzoFerber

(usa FreeBSD)

Enviado em 01/01/2015 - 22:37h

danielcrvg escreveu:

...
obrigado pela informação... eu nao sabia que o ponteiro para um char tem o tamanh de de 8 bytes (64 bits)
...



Não só o ponteiro do char. QUALQUER ponteiro em uma arquitetura de 64bits tem 64bits (8 bytes).

Qualquer ponteiro em uma arquitetura de 32 bits tem 32 bits (4 bytes).

*

A arquitetura do computador define quantos endereços de memória o processador pode acessar, então, qualquer endereço de memória terá aquela quantidade exata de bits.

Por isso arquiteturas de 32bits estão limitadas a 4GiB de RAM.

2^32 = 4294967296 bytes = 4194304 kilobytes = 4096 megabytes = 4 GiB.


8. Re: mais duvidas sobre ponteiros rs [RESOLVIDO]

Daniel
danielcrvg

(usa Slackware)

Enviado em 01/01/2015 - 22:48h

EnzoFerber escreveu:



int main(){

char xxx[]="daniel";
int i = 0;
char *ptnome;
ptnome=&xxx;

printf("ENDENTENDO O BASICO SOBRE PONTEIROS\n");

printf("\n\n.:[ STRINGS ]:.\n");
printf("\nConteudo de 'xxx' (%%s, xxx): %s\n",xxx);
printf("Endereco de 'xxx' (%%p, &xxx): %p\n",&xxx);
ptnome=&xxx;
printf("Endereço de 'ptnome' (%%p, &ptnome): %p\n",&ptnome);
printf("Conteudo de 'ptnome (%%s, ptnome)': %s\n",ptnome);
printf("Endereço que 'ptnome' aponta (%%p, ptnome): %p\n\n",ptnome);

int zzz=10;
int *ptzzz;
printf("\n.:[ INTEIROS ]:.\n");
printf("\nConteudo de 'zzz' (%%d, zzz): %d\n",zzz);
printf("Endereco de 'zzz' (%%p, &zzz): %p\n",&zzz);

ptzzz=&zzz;
printf("Endereço de 'ptzzz' (%%p, &ptzzz): %p\n",&ptzzz);
printf("Conteudo de 'ptzzz' (%%d, *ptzzz): %d\n",*ptzzz);
printf("Endereço que 'ptzzz' aponta (%%p, ptzzz): %p\n",ptzzz);

printf("\n--------------------------------\n");
printf("Primeiro elemento de 'xxx': %c\n",xxx[0]);
printf("Endereco do 1 elemento: %p\n",&xxx[0]);
printf("Endereco do vetor: %p\n",&xxx);


printf("\nImprimindo elementos da string com ponteiros: \n");
for (i=0;i<strlen(xxx);i++) {
printf("%c : %p : %d\n",ptnome[i],&ptnome[i],sizeof(ptnome[i]));
}
char nome2[6]={'d','a','n','i','e','l'};
char *ptnome2;
ptnome2=&nome2;
i = 0;

printf("\nImprimindo elementos do vetor de char com ponteiros: \n");
for (i=0;i<strlen(xxx);i++) {
printf("%c : %p : %d\n",ptnome2[i],&ptnome2[i],sizeof(ptnome2[i]));
}

return 0;
}



O meu output:


ENDENTENDO O BASICO SOBRE PONTEIROS


.:[ STRINGS ]:.

Conteudo de 'xxx' (%s, xxx): daniel
Endereco de 'xxx' (%p, &xxx): 0x7fff5c72fc15
Endereço de 'ptnome' (%p, &ptnome): 0x7fff5c72fc08
Conteudo de 'ptnome (%s, ptnome)': daniel
Endereço que 'ptnome' aponta (%p, ptnome): 0x7fff5c72fc15


.:[ INTEIROS ]:.

Conteudo de 'zzz' (%d, zzz): 10
Endereco de 'zzz' (%p, &zzz): 0x7fff5c72fc04
Endereço de 'ptzzz' (%p, &ptzzz): 0x7fff5c72fbf8
Conteudo de 'ptzzz' (%d, *ptzzz): 10
Endereço que 'ptzzz' aponta (%p, ptzzz): 0x7fff5c72fc04

--------------------------------
Primeiro elemento de 'xxx': d
Endereco do 1 elemento: 0x7fff5c72fc15
Endereco do vetor: 0x7fff5c72fc15

Imprimindo elementos da string com ponteiros:
d : 0x7fff5c72fc15 : 1
a : 0x7fff5c72fc16 : 1
n : 0x7fff5c72fc17 : 1
i : 0x7fff5c72fc18 : 1
e : 0x7fff5c72fc19 : 1
l : 0x7fff5c72fc1a : 1

Imprimindo elementos do vetor de char com ponteiros:
d : 0x7fff5c72fbf2 : 1
a : 0x7fff5c72fbf3 : 1
n : 0x7fff5c72fbf4 : 1
i : 0x7fff5c72fbf5 : 1
e : 0x7fff5c72fbf6 : 1
l : 0x7fff5c72fbf7 : 1


O ultimo código eu editei, esqueci de colocar o [ i ] na primeira referencia do ponteiro.

*

Ah, e não são apenas ponteiros para char que têm 8 bytes não. Todos os ponteiros em arquiteturas de 64bits tem 8 bytes.


[]'s



kkkk ele ta de sacanagem com a minha cara entao.. olha o meu output:


Primeiro elemento de 'xxx': d
Endereco do 1 elemento: 0x7fff98e3d120
Endereco do vetor: 0x7fff98e3d120

Imprimindo elementos da string com ponteiros:
d : 0x7fff98e3d120 : 1
a : 0x7fff98e3d122 : 1
n : 0x7fff98e3d124 : 1
i : 0x7fff98e3d126 : 1
e : 0x7fff98e3d128 : 1
l : 0x7fff98e3d12a : 1

Imprimindo elementos do vetor de char com ponteiros:
d : 0x7fff98e3d100 : 1
a : 0x7fff98e3d102 : 1
n : 0x7fff98e3d104 : 1
i : 0x7fff98e3d106 : 1
e : 0x7fff98e3d108 : 1
l : 0x7fff98e3d10a : 1





9. Re: mais duvidas sobre ponteiros rs [RESOLVIDO]

Daniel
danielcrvg

(usa Slackware)

Enviado em 01/01/2015 - 22:57h


int main(){

char xxx[]="daniel";
int i = 0;
char *ptnome;
ptnome=&xxx;

printf("ENDENTENDO O BASICO SOBRE PONTEIROS\n");

printf("\n\n.:[ STRINGS ]:.\n");
printf("\nConteudo de 'xxx' (%%s, xxx): %s\n",xxx);
printf("Endereco de 'xxx' (%%p, &xxx): %p\n",&xxx);
ptnome=&xxx;
printf("Endereço de 'ptnome' (%%p, &ptnome): %p\n",&ptnome);
printf("Conteudo de 'ptnome (%%s, ptnome)': %s\n",ptnome);
printf("Endereço que 'ptnome' aponta (%%p, ptnome): %p\n\n",ptnome);

int zzz=10;
int *ptzzz;
printf("\n.:[ INTEIROS ]:.\n");
printf("\nConteudo de 'zzz' (%%d, zzz): %d\n",zzz);
printf("Endereco de 'zzz' (%%p, &zzz): %p\n",&zzz);

ptzzz=&zzz;
printf("Endereço de 'ptzzz' (%%p, &ptzzz): %p\n",&ptzzz);
printf("Conteudo de 'ptzzz' (%%d, *ptzzz): %d\n",*ptzzz);
printf("Endereço que 'ptzzz' aponta (%%p, ptzzz): %p\n",ptzzz);

printf("\n--------------------------------\n");
printf("Primeiro elemento de 'xxx': %c\n",xxx[0]);
printf("Endereco do 1 elemento: %p\n",&xxx[0]);
printf("Endereco do vetor: %p\n",&xxx);


printf("\nImprimindo elementos da string com ponteiros: \n");
for (i=0;i<strlen(xxx);i++) {
printf("%c : %p : %d\n",ptnome[i],&ptnome[i],sizeof(ptnome[i]));
}
char nome2[6]={'d','a','n','i','e','l'};
char *ptnome2;
ptnome2=&nome2;
i = 0;

printf("\nImprimindo elementos do vetor de char com ponteiros: \n");
for (i=0;i<strlen(xxx);i++) {
printf("%c : %p : %d\n",ptnome2[i],&ptnome2[i],sizeof(ptnome2[i]));
}

return 0;
}


Tipo assim deu certinho o que eu queria... eu acho que quando eu tava incrementando o ponteiro assim *ptnome++ ele tava aumentando em 1 bloco o vetor, e nao incrementando a posicao sei la... por isso tava de 2 em 2..

mas do seu jeito assim:
printf("%c : %p : %d\n",ptnome[i],&ptnome[i],sizeof(ptnome[i])); 


deu certo...

obrigadao



10. Re: mais duvidas sobre ponteiros rs [RESOLVIDO]

Enzo de Brito Ferber
EnzoFerber

(usa FreeBSD)

Enviado em 01/01/2015 - 23:17h

Opa.

No seu código você incrementava a referencia do ponteiro e depois adicionava um offset i a ele. Então, a cada interação você aumentava em 2 o salto.

Imagine que seu ponteiro está no endereço 0x01.

Quando você faz:

*p++, ele vai imprimir o valor que existe em (p) e depois irá *incrementar* a referencia. Ou seja, logo após essa impressão, p apontará para o endereço 0x02. Então, a próxima instrução é imprimir o valor do endereço (p + i). Traduzindo, endereço 0x02 + 1 = 0x03.


for (i=0;i<strlen(xxx);i++) {
printf("%c : %p\n",*ptnome++,&ptnome[ i ]);
}

...

Vamos por iteração: (considere também que ptnome tem endereço inicial 0x01.)

i = 0
imprime *ptnome que esta no endereço 0x01 e logo após incrementa o endereço (que passa a ser 0x02 depois da impressão)
imprime endereço de ptnome[ i ], ou seja ( 0x02 + 0 ) = 0x02.

i = 1
imprime *ptnome que esta no endereço 0x02 e logo após incrementa o endereço (que passa a ser 0x03 depois da impressao)
imprime endereço de ptnome[ i ], ou seja (0x03 + 1) = 0x04

i = 2
imprime *ptnome que esta no endereço 0x03 e logo após incrementa o endereço (que passa a ser 0x04 depois da impressão )
imprime endereço de ptnome[ i ], ou seja ( 0x04 + 2) = 0x06

i = 3
imprime *ptnome que esta no endereço 0x04 e logo apos incrementa o endereço ( que passa a ser 0x05 depois da impressão )
imprime endereço de ptnome[ i ], ou seja ( 0x05 + 3 ) = 0x08

i = n...



Conseguiu entender o que estava acontecendo no seu programa?

[]'s


11. Re: mais duvidas sobre ponteiros rs [RESOLVIDO]

Daniel
danielcrvg

(usa Slackware)

Enviado em 01/01/2015 - 23:20h

EnzoFerber escreveu:

Opa.

No seu código você incrementava a referencia do ponteiro e depois adicionava um offset i a ele. Então, a cada interação você aumentava em 2 o salto.

Imagine que seu ponteiro está no endereço 0x01.

Quando você faz:

*p++, ele vai imprimir o valor que existe em (p) e depois irá *incrementar* a referencia. Ou seja, logo após essa impressão, p apontará para o endereço 0x02. Então, a próxima instrução é imprimir o valor do endereço (p + i). Traduzindo, endereço 0x02 + 1 = 0x03.


for (i=0;i<strlen(xxx);i++) {
printf("%c : %p\n",*ptnome++,&ptnome[ i ]);
}

...

Vamos por iteração: (considere também que ptnome tem endereço inicial 0x01.)

i = 0
imprime *ptnome que esta no endereço 0x01 e logo após incrementa o endereço (que passa a ser 0x02 depois da impressão)
imprime endereço de ptnome[ i ], ou seja ( 0x02 + 0 ) = 0x02.

i = 1
imprime *ptnome que esta no endereço 0x02 e logo após incrementa o endereço (que passa a ser 0x03 depois da impressao)
imprime endereço de ptnome[ i ], ou seja (0x03 + 1) = 0x04

i = 2
imprime *ptnome que esta no endereço 0x03 e logo após incrementa o endereço (que passa a ser 0x04 depois da impressão )
imprime endereço de ptnome[ i ], ou seja ( 0x04 + 2) = 0x06

i = 3
imprime *ptnome que esta no endereço 0x04 e logo apos incrementa o endereço ( que passa a ser 0x05 depois da impressão )
imprime endereço de ptnome[ i ], ou seja ( 0x05 + 3 ) = 0x08

i = n...



Conseguiu entender o que estava acontecendo no seu programa?

[]'s



aham... valeu irmao. obrigado!!




12. Re: mais duvidas sobre ponteiros rs [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 02/01/2015 - 00:11h

danielcrvg escreveu:

( ... )

- Vetor de char vs String ..

As diferencas que eu entendi:

Strings sao definidas como char e os dados ficam entre " " e vetor de chars ' ', exemplo:

char nome[] = "daniel";

em quanto vetor de chars:

char nome[] = {'d','a'.'n','i','e','l'};

Nas strings, quando não se define o tamanho, o compilador automaticamente ja coloca o 'barra0' no final dela.


Na verdade, não é bem isso.

O fato incontornável é que C não possui um tipo específico para strings. Todo string em C é um array de caracteres (podendo ser declarado como tal ou ser um bloco alocado dinamicamente e manipulado através de um ponteiro). A única coisa que distingue um vetor que contém um string de outro que é mera coleção de caracteres é a presença (ou a expectativa da presença) do terminador, que é um caráter de valor inteiro igual a zero.

char arr1[]="daniel";
char arr2[]={'d', 'a', 'n', 'i', 'e', 'l'};
char arr3[]={100, 97, 110, 105, 101, 108};
char arr4[]={'d', 'a', 'n', 'i', 'e', 'l', 0};
char arr3[]={100, 97, 110, 105, 101, 108, 0};

/* (sizeof arr1)==7, arr1 pode ser usado como string. */
/* (sizeof arr2)==6, arr2 não deve ser usado como string. */
/* (sizeof arr3)==6, arr3 não deve ser usado como string. */
/* Os conteúdos de arr2 e arr3 são idênticos. */
/* (sizeof arr4)==7, arr4 pode ser usado como string. */
/* (sizeof arr5)==7, arr5 pode ser usado como string. */
/*
Os conteúdos de arr1, arr4 e arr5 são idênticos, mas existe
uma diferença entre eles: o conteúdo de arr1 é constante, mesmo
tendo sido declarado sem a palavra-chave const (em C; se fosse
C++, a especificação de const na delcaração de arr1 seria
obrigatória).
*/


A sintaxe de texto entre aspas é uma conveniência oferecida pela linguagem para simplificar a definição e o uso de arrays de caracteres constantes destinados a representar strings. Os caracteres entre aspas são dispostos sequencialmente na memória, e automaticamente sucedidos por um caráter nulo. Além disso, o tipo de uma expressão como "daniel" (incluindo as aspas) é endereço (ou ponteiro) para caráter, com a informação adicional de que esse caráter é o primeiro de um bloco de sete caracteres que constituem o array.

Bom agora vem minha duvida:

    char xxx[]="daniel";
int i = 0;
char *ptnome;
ptnome=&xxx;


Aqui você cometeu um erro. O certo seria fazer ptnome=xxx. Num outro tópico aberto por você aqui no fórum, eu disse que é errado usar o operador de obtenção de endereço de variável (&) sobre o nome de um array, porque esse nome não constitui uma variável, mas sim uma representação constante de um endereço.

No entanto, provavelmente o seu código compilou e até possivelmente rodou. Então que estória é essa que eu estou contando, de que não pode fazer do jeito como você fez?

Bom, esse é um daqueles lugares em que o C é um tanto obscuro. Se não entender parte do que eu vou apresentar, não se acanhe nem desista do C (essas coisas obscuras têm sua utilidade no momento certo -- que geralmente não é quando se é iniciante).

Existe um caso em que é válido aplicar & sobre algo declarado com aspecto de array, que é quando o objeto declarado é parâmetro de função. Veja o exemplo.

void func(char param[10]){
char arr[10]="Um string"; /* 9 caracteres + terminador. */

char *p1, *p2, *p3, *p4;
p1=arr; /* OK: ponteiro para char recebe endereço de char
(primeiro elemento do bloco indicado por “arr”). */
p2=&arr; /* Problema: não faz sentido usar & em constante,
mas o compilador permite. No entanto isso causa
um erro de tipo de dados. */
p3=param; /* OK: ponteiro para char recebe endereço de char. */
p4=&param; /* Erro de tipo (apesar da forma de array usada na de-
claração, o tipo de param é char *). */

char (*pac1)[10], (*pac2)[10];
pac1=&arr; /* Problema: não faz sentido usar & em constante,
mas aqui não existe mais o erro de tipo. */
pac2=&param; /* Erro de tipo (ver abaixo). */

char **ppc1, **ppc2;
ppc1=&arr; /* Problema: não faz sentido usar & em constante,
e ainda existe uma incompatibilidade de tipos. */
ppc2=&param; /* OK: param tem seu próprio endereço e é um char *,
então &param é compatível com char **. */

printf("p1=%p\n", p1);
printf("p2=%p\n", p2);
printf("p3=%p\n", p3);
printf("p4=%p\n\n", p4);

printf("pac1=%p\n", pac1);
printf("pac2=%p\n\n", pac2);

printf("ppc1=%p\n", ppc1);
printf("ppc2=%p\n", ppc2);
}


A aparente doideira começa na já primeira linha: você diz que o parâmetro param é um array de dez caracteres, mas o compilador entende que ele é um mero ponteiro para caracteres, e permite que você chame a função com um argumento array de caracteres de qualquer tamanho ou, na verdade, com qualquer ponteiro. Mas por quê?

Porque se o compilador exigisse que o argumento fosse declarado com o mesmo aspecto da declaração do parâmetro, isso impediria chamar a função com um argumento dinamicamente alocado. Dito de outro modo, se o fato de o parâmetro ter a forma de um array com dez elementos obrigasse os argumentos a serem arrays com dez argumentos, você não poderia ter o seguinte código -- ainda que ele seja logicamente válido.

char *dyn_array;
dyn_array=calloc(10, 1); /* (sizeof char)==1 por definição */
func(dyn_array); /* Chamo a função com um array dinâmico com
exatamente 10 elementos. Por quê não? */


Então, a declaração da função func(), acima, acaba fazendo com que a forma de array seja só um comentário de luxo, e normalmente é usada somente quando o número esperado de elementos tem de ser fixo. Na prática, ela é funcionalmente idêntica ao que se teria se a declaração tivesse sido a seguinte.

void func(*param) 


Um dos aspectos dessa equivalência é o fato de que param passa a ser uma variável ponteiro dentro da função. Como tal, não apenas o seu valor pode ser manipulado e alterado, mas também possui um endereço próprio, que pode ser obtido com &. No entanto, a opção pela sintaxe de array tem uma implicação mais profunda, não apenas nesse código, mas sobre a linguagem como um todo.

A implicação é esta: se um parâmetro de função pode ser declarado como array e, ainda assim, pode receber a aplicação do operador &, então qualquer array, declarado em qualquer parte do programa (quer como parâmetro, quer como variável estática, quer como variável automática, quer como campo de uma estrutura), também pode. Nos casos em que o nome do array X com N elementos não indicar uma variável (porque é constante), então o endereço resultando da expressão &X deve ser idêntico ao endereço da expressão X; entretanto, o tipo de &X não será igual ao tipo de X, mas sim “ponteiro para array com N elementos do mesmo tipo que X[0]. Então, se você tiver

int arr_int[15]; 


, terá que arr_int e &arr_int designam o mesmo endereço, mas o tipo de arr_int é “array com 15 elementos inteiros”, ao passo que &arr_int é do tipo “ponteiro para array com 15 elementos inteiros”.

(Eu não sei se existe uma justificativa plausível para tal comportamento, definido pelo comitê de padronização da linguagem C. Lendo as memórias do falecido Dennis Ritchie, criador do C, parece que duas linhas que orientaram o projeto original da linguagem C e dos primeiros compiladores foram a consistência de operações entre os diferentes tipos de dados, incluindo arrays e estruturas, e a construção de compiladores simples, que não impusessem limitações ao usuário ao custo de aumentar muito sua complexidade. No entanto, eu não creio que os princípios de Ritchie se apliquem nesse caso: tanto para transformar array na lista de parâmetros em ponteiros quanto para tratar não-variáveis como se variáveis fossem, o compilador tem de ter código especializado. Minha opinião pessoal é de aceitação sem entusiasmo do primeiro caso e radicalmente contrária ao segundo, porque cria inconsistência e abre espaço para erros acidentais.)

Dentro da função, eu trabalhei com três tipos de ponteiros: ponteiro para caracteres (char *), ponteiro para arrays de caracteres com dez elementos (char (*)[10]) e ponteiro para ponteiro de caracteres (char **), e experimentei fazer atribuições a eles com os valores de arr, param, &arr e &param.

Por razões históricas, o C é relativamente leniente com atribuições entre ponteiros de tipos diferentes (e, às vezes, até entre ponteiros e inteiros). É possível que você não receba erro ou aviso nenhum ao tentar compilar a função func() que eu mostrei. É comum que alertas sobre essas operações só sejam mostrados se você usar certas opções de compilação que servem para identificar e alertar sobre código potencialmente perigoso (com o GCC, eu geralmente recomendo as opções “-Wall”, que habilita todos os avisos, “-Werror”, que transforma os avisos em erros, o que obriga a tratar os avisos recebidos, “-O2”, que ajuda a detectar variáveis não inicializadas ou blocos de código redundantes, e, às vezes, “-pedantic”, que avisa sobre construções que, apesar de válidas, poderiam dar problema se usadas com outro compilador).

Se você tiver compilado (sem as opções de diagnóstico) e tido a curiosidade de chamar a função func(), provavelmente viu uma saída parecida com a seguinte.

p1=0x7fffdc074900
p2=0x7fffdc074900
p3=0x4007b6
p4=0x7fffdc0748b8

pac1=0x7fffdc074900
pac2=0x7fffdc0748b8

ppc1=0x7fffdc074900
ppc2=0x7fffdc0748b8


É interessante notar que os valores dos ponteiros p1, p2, pac1 e ppc1 são idênticos, embora p1 tenha sido obtido de arr e os demais a partir de &arr. Isso difere do que ocorreu com p3, p4, pac2 e ppc2, em que o primeiro recebeu o valor de param, que é uma cópia do ponteiro (na verdade, um array constante) usado para invocar a função, e os outros recebem o endereço de onde o valor recebido ficou guardado durante a execução da função.

Compilando com as opções de diagnóstico que alertam a respeito ou inibem o uso leniente de ponteiros, pode-se ver as inconsistências.

$ gcc -Wall -Werror -o lixo lixo.c -std=c11
lixo.c: In function ‘func’:
lixo.c:10:5: error: assignment from incompatible pointer type [-Werror]
p2=&arr; /* Problema: não faz sentido usar & em constante,
^
lixo.c:15:5: error: assignment from incompatible pointer type [-Werror]
p4=&param; /* Erro de tipo. */
^
lixo.c:20:7: error: assignment from incompatible pointer type [-Werror]
pac2=&param; /* OK: obtém o endereço onde a função guarda o
^
lixo.c:24:7: error: assignment from incompatible pointer type [-Werror]
ppc1=&arr; /* Problema: não faz sentido usar & em constante,
^
cc1: all warnings being treated as errors


Se você compilar o seu programa com as mesmas opções, vai obter indicações de erro semelhantes.

    printf("ENDENTENDO O BASICO SOBRE PONTEIROS\n");

printf("\n\n.:[ STRINGS ]:.\n");
printf("\nConteudo de 'xxx' (%%s, xxx): %s\n",xxx);
printf("Endereco de 'xxx' (%%p, &xxx): %p\n",&xxx);
ptnome=&xxx;
printf("Endereço de 'ptnome' (%%p, &ptnome): %p\n",&ptnome);
printf("Conteudo de 'ptnome (%%s, ptnome)': %s\n",ptnome);
printf("Endereço que 'ptnome' aponta (%%p, ptnome): %p\n\n",ptnome);

int zzz=10;
int *ptzzz;
printf("\n.:[ INTEIROS ]:.\n");
printf("\nConteudo de 'zzz' (%%d, zzz): %d\n",zzz);
printf("Endereco de 'zzz' (%%p, &zzz): %p\n",&zzz);

ptzzz=&zzz;
printf("Endereço de 'ptzzz' (%%p, &ptzzz): %p\n",&ptzzz);
printf("Conteudo de 'ptzzz' (%%d, *ptzzz): %d\n",*ptzzz);
printf("Endereço que 'ptzzz' aponta (%%p, ptzzz): %p\n",ptzzz);

printf("\n--------------------------------\n");
printf("Primeiro elemento de 'xxx': %c\n",xxx[0]);
printf("Endereco do 1 elemento: %p\n",&xxx[0]);
printf("Endereco do vetor: %p\n",&xxx);


printf("\nImprimindo elementos da string com ponteiros: \n");
for (i=0;i<strlen(xxx);i++) {
printf("%c : %p\n",*ptnome++,&ptnome);
}
char nome2[6]={'d','a','n','i','e','l'};
char *ptnome2;
ptnome2=&nome2;
i = 0;

printf("\nImprimindo elementos do vetor de char com ponteiros: \n");
for (i=0;i<strlen(xxx);i++) {
printf("%c : %p\n",*ptnome2++,&ptnome2[i]);


Esse “++” depois de [i]ptnome2
parece estar sobrando. Não creio que ele se adeque ao que você quer imprimir.

[quote]
    }

printf("\nTamanho de um char: %d\n",sizeof(char));

return 0;
}


Na primeira parte eu apenas imprimi na tela valores, enderecos de memoria, etc apenas para manipular os ponteiros..

Ai quando eu resolvi imprimir o vetor de char que me bateu a duvida:

Se o char tem apenas 1 byte, pq o seu endereco de memoria esta sendo de 2 em 2, ao inves de ser de 1 em 1 ??


Respondido acima.

Tipo uma string mesmo com 1 caracter tem tamanho dois, por que é o caracter + o 'barra0' delimitador do tamanho certo?

Mas o tipo char nao é apenas 1 byte??


Veja a explicação lá em cima sobre o uso conveniente de texto entre aspas.



01 02



Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts