Diferença de vetores e ponteiros #16

Open
opened 2025-05-28 22:08:52 -03:00 by NRZCode · 7 comments

Blau, veja que interessante sobre as particularidades entre vetores e ponteiros.

Sabemos que ponteiros são armazenados em .rodata e por isso não conseguimos modificar seu conteúdo por índices

int main(void) {
    char *str = "banana";
    str[2] = 'c';                   // Isso causa falha de segmentação
}

Porém, é possível reatribuir a cadeia de string inteira, da forma

int main(void) {
    char *str = "banana";
    str = "abacate";                        // Isso não causa falha de segmentação
    printf("%s\n", str);
}

O que acontece no segundo exemplo?
Esse endereço do ponteiro é modificado em tempo de execução?
Pq o espaço alocado na compilação foi do tamanho de "banana" do início.

Blau, veja que interessante sobre as particularidades entre vetores e ponteiros. Sabemos que ponteiros são armazenados em .rodata e por isso não conseguimos modificar seu conteúdo por índices ```c int main(void) { char *str = "banana"; str[2] = 'c'; // Isso causa falha de segmentação } ``` Porém, é possível reatribuir a cadeia de string inteira, da forma ```c int main(void) { char *str = "banana"; str = "abacate"; // Isso não causa falha de segmentação printf("%s\n", str); } ``` O que acontece no segundo exemplo? Esse endereço do ponteiro é modificado em tempo de execução? Pq o espaço alocado na compilação foi do tamanho de "banana" do início.
Author

Já vi que o endereço de ptr não muda

int main(void) {
    char *ptr = "banana";
    printf("%s -> %p\n", ptr, &ptr);

    ptr = "abacate";
    printf("%s -> %p\n", ptr, &ptr);

}
$ ./ponteiro 
banana -> 0x7ffcb861ed08
abacate -> 0x7ffcb861ed08
Já vi que o endereço de ptr não muda ```c int main(void) { char *ptr = "banana"; printf("%s -> %p\n", ptr, &ptr); ptr = "abacate"; printf("%s -> %p\n", ptr, &ptr); } ``` ```text $ ./ponteiro banana -> 0x7ffcb861ed08 abacate -> 0x7ffcb861ed08 ```
Owner

@NRZCode wrote in #16 (comment):

O que acontece no segundo exemplo?

O endereço de outra string é atribuído ao ponteiro.

Esse endereço do ponteiro é modificado em tempo de execução?

O endereço do ponteiro, não, só o endereço no ponteiro. ;-)

Pq o espaço alocado na compilação foi do tamanho de "banana" do início.

Não foi alocado espaço... O ponteiro recebeu o endereço da string "banana" e depois o endereço da string "abacate", ambas do tipo char *.

@NRZCode wrote in https://bolha.dev/blau_araujo/cblc/issues/16#issue-16: > O que acontece no segundo exemplo? O endereço de outra string é atribuído ao ponteiro. > Esse endereço do ponteiro é modificado em tempo de execução? O endereço do ponteiro, não, só o endereço no ponteiro. ;-) > Pq o espaço alocado na compilação foi do tamanho de "banana" do início. Não foi alocado espaço... O ponteiro recebeu o endereço da string "banana" e depois o endereço da string "abacate", ambas do tipo `char *`.

@NRZCode, na minha opinião, o segundo código, são coisas diferentes, apesar de *ponteiro ser uma variável:

*str = "banana"; // ponteiro, deveria apontar para um endereço, e está atribuindo uma string
str = "abacate"; // nome de uma variável, aqui uma variável declarada chamada str.

Então ao meu ver, não mudou nada em tempo de execução, apenas atribuiu um valor a uma variável de nome "str", com valor "abacate", e fazendo uma verificação do binário, com o comando:

readelf -x .rodata a.out 

Despejo máximo da secção ".rodata":
  0x00002000 01000200 62616e61 6e610061 62616361 ....banana.abaca
  0x00002010 746500                              te.

Saída do comando:

readelf -x .text a.out 

Despejo máximo da secção ".text":
  0x00001050 31ed4989 d15e4889 e24883e4 f0505445 1.I..^H..H...PTE
  0x00001060 31c031c9 488d3dce 000000ff 154f2f00 1.1.H.=......O/.
  0x00001070 00f4662e 0f1f8400 00000000 0f1f4000 ..f...........@.
  0x00001080 488d3d91 2f000048 8d058a2f 00004839 H.=./..H.../..H9
  0x00001090 f8741548 8b052e2f 00004885 c07409ff .t.H.../..H..t..
  0x000010a0 e00f1f80 00000000 c30f1f80 00000000 ................
  0x000010b0 488d3d61 2f000048 8d355a2f 00004829 H.=a/..H.5Z/..H)
  0x000010c0 fe4889f0 48c1ee3f 48c1f803 4801c648 .H..H..?H...H..H
  0x000010d0 d1fe7414 488b05fd 2e000048 85c07408 ..t.H......H..t.
  0x000010e0 ffe0660f 1f440000 c30f1f80 00000000 ..f..D..........
  0x000010f0 f30f1efa 803d1d2f 00000075 2b554883 .....=./...u+UH.
  0x00001100 3dda2e00 00004889 e5740c48 8b3dfe2e =.....H..t.H.=..
  0x00001110 0000e829 ffffffe8 64ffffff c605f52e ...)....d.......
  0x00001120 0000015d c30f1f00 c30f1f80 00000000 ...]............
  0x00001130 f30f1efa e977ffff ff554889 e54883ec .....w...UH..H..
  0x00001140 10488d05 bc0e0000 488945f8 488d05b8 .H......H.E.H...
  0x00001150 0e000048 8945f848 8b45f848 89c7e8cd ...H.E.H.E.H....
  0x00001160 feffffb8 00000000 c9c3              ..........

A 'str = "abacate"', também está na área read only.

E ai Blau, o que você nos diz?

@NRZCode, na minha opinião, o segundo código, são coisas diferentes, apesar de *ponteiro ser uma variável: *str = "banana"; // ponteiro, deveria apontar para um endereço, e está atribuindo uma string str = "abacate"; // nome de uma variável, aqui uma variável declarada chamada str. Então ao meu ver, não mudou nada em tempo de execução, apenas atribuiu um valor a uma variável de nome "str", com valor "abacate", e fazendo uma verificação do binário, com o comando: ``` readelf -x .rodata a.out Despejo máximo da secção ".rodata": 0x00002000 01000200 62616e61 6e610061 62616361 ....banana.abaca 0x00002010 746500 te. ``` Saída do comando: ``` readelf -x .text a.out Despejo máximo da secção ".text": 0x00001050 31ed4989 d15e4889 e24883e4 f0505445 1.I..^H..H...PTE 0x00001060 31c031c9 488d3dce 000000ff 154f2f00 1.1.H.=......O/. 0x00001070 00f4662e 0f1f8400 00000000 0f1f4000 ..f...........@. 0x00001080 488d3d91 2f000048 8d058a2f 00004839 H.=./..H.../..H9 0x00001090 f8741548 8b052e2f 00004885 c07409ff .t.H.../..H..t.. 0x000010a0 e00f1f80 00000000 c30f1f80 00000000 ................ 0x000010b0 488d3d61 2f000048 8d355a2f 00004829 H.=a/..H.5Z/..H) 0x000010c0 fe4889f0 48c1ee3f 48c1f803 4801c648 .H..H..?H...H..H 0x000010d0 d1fe7414 488b05fd 2e000048 85c07408 ..t.H......H..t. 0x000010e0 ffe0660f 1f440000 c30f1f80 00000000 ..f..D.......... 0x000010f0 f30f1efa 803d1d2f 00000075 2b554883 .....=./...u+UH. 0x00001100 3dda2e00 00004889 e5740c48 8b3dfe2e =.....H..t.H.=.. 0x00001110 0000e829 ffffffe8 64ffffff c605f52e ...)....d....... 0x00001120 0000015d c30f1f00 c30f1f80 00000000 ...]............ 0x00001130 f30f1efa e977ffff ff554889 e54883ec .....w...UH..H.. 0x00001140 10488d05 bc0e0000 488945f8 488d05b8 .H......H.E.H... 0x00001150 0e000048 8945f848 8b45f848 89c7e8cd ...H.E.H.E.H.... 0x00001160 feffffb8 00000000 c9c3 .......... ``` A 'str = "abacate"', também está na área read only. E ai Blau, o que você nos diz?
Author

@blau_araujo wrote in #16 (comment):

O endereço de outra string é atribuído ao ponteiro.

Perfeito, Blau.
Agora me recordo de outro exemplo que vi, onde era declarado um vetor de char e seu endereço era atribuído a um ponteiro.
Assim toda manipulação dos caracteres era possível.

Eu ainda estou confundindo a impressão do endereço de ponteiro e vetor usando o & a frente da variável.

// A diferença do uso do & para imprimir endereço
printf("%s -> %p\n", ptr, &ptr);
// Imprime o endereço do ponteiro
printf("%s -> %p\n", ptr, ptr);
@blau_araujo wrote in https://bolha.dev/blau_araujo/cblc/issues/16#issuecomment-21: > O endereço de outra string é atribuído ao ponteiro. Perfeito, Blau. Agora me recordo de outro exemplo que vi, onde era declarado um vetor de char e seu endereço era atribuído a um ponteiro. Assim toda manipulação dos caracteres era possível. Eu ainda estou confundindo a impressão do endereço de ponteiro e vetor usando o & a frente da variável. ```c // A diferença do uso do & para imprimir endereço printf("%s -> %p\n", ptr, &ptr); // Imprime o endereço do ponteiro printf("%s -> %p\n", ptr, ptr); ```
Author

@drginfo wrote in #16 (comment):

Então ao meu ver, não mudou nada em tempo de execução, apenas atribuiu um valor a uma variável de nome "str", com valor "abacate", e fazendo uma verificação do binário, com o comando:

Mudou em tempo de execução.
Mudou o endereço que no começo da execução aponta pro endereço de banana e após aponta pro endereço de abacate.
Ambas strings estão armazenadas em rodata.
Então o que muda não é a atribuição da string à ptr e sim o endereço.

@drginfo wrote in https://bolha.dev/blau_araujo/cblc/issues/16#issuecomment-22: > Então ao meu ver, não mudou nada em tempo de execução, apenas atribuiu um valor a uma variável de nome "str", com valor "abacate", e fazendo uma verificação do binário, com o comando: Mudou em tempo de execução. Mudou o endereço que no começo da execução aponta pro endereço de banana e após aponta pro endereço de abacate. Ambas strings estão armazenadas em rodata. Então o que muda não é a atribuição da string à ptr e sim o endereço.
Owner

@drginfo wrote in #16 (comment):

na minha opinião, o segundo código, são coisas diferentes, apesar de *ponteiro ser uma variável:

*str = "banana"; // ponteiro, deveria apontar para um endereço, e está atribuindo uma string str = "abacate"; // nome de uma variável, aqui uma variável declarada chamada str.

Não...str é apenas o ponteiro sendo usado para receber outro endereço, não há uma segunda variável.

@drginfo wrote in https://bolha.dev/blau_araujo/cblc/issues/16#issuecomment-22: > na minha opinião, o segundo código, são coisas diferentes, apesar de *ponteiro ser uma variável: > > *str = "banana"; // ponteiro, deveria apontar para um endereço, e está atribuindo uma string str = "abacate"; // nome de uma variável, aqui uma variável declarada chamada str. Não...`str` é apenas o ponteiro sendo usado para receber outro endereço, não há uma segunda variável.
Owner

@NRZCode wrote in #16 (comment):

Eu ainda estou confundindo a impressão do endereço de ponteiro e vetor usando o & a frente da variável.

A sintaxe &str refere-se ao endereço na pilha onde o endereço em str será escrito.

Do mesmo modo isso:

int a = 42;

A sintaxe a avalia o valor associado à variável, enquanto &a refere-se ao endereço na pilha onde o valor será escrito.

@NRZCode wrote in https://bolha.dev/blau_araujo/cblc/issues/16#issuecomment-23: > Eu ainda estou confundindo a impressão do endereço de ponteiro e vetor usando o & a frente da variável. A sintaxe `&str` refere-se ao endereço na pilha onde o endereço em `str` será escrito. Do mesmo modo isso: ``` int a = 42; ``` A sintaxe `a` avalia o valor associado à variável, enquanto `&a` refere-se ao endereço na pilha onde o valor será escrito.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: blau_araujo/cblc#16
No description provided.