ponteiro char

1. ponteiro char

fiewhifwe
Henriquemh

(usa Ubuntu)

Enviado em 27/06/2013 - 09:05h

Bom, estou com uma dúvida, tipo,
eu declaro

#include <iostream>
using namespace std;
main()
{
char *s="Andre";
}

ele da um erro
warning: deprecated conversion from string constant to ‘char*’ 

mais eu vi em vários livros e até mesmo na internet, eles fazem desse jeito, único jeito que deu certo aqui seria
#include <iostream>
using namespace std;
main()
{
char *s;
char nome[10]="Marcos";
s=nome;
cout <<s;
}



  


2. Re: ponteiro char

Uilian Ries
uilianries

(usa Linux Mint)

Enviado em 27/06/2013 - 09:15h

O compilador está dizendo que você está tentando atribuir uma const char * para um char *, de forma implicita.

Resolva assim:


const char * s = {"Andre"};


Desta maneira vai estar atribuido diretamente para um const char, porém por ser constante não poderá mudar valor.

Na verdade é possível mudar usando um const_cast, porém não é elegante e nem seguro.


3. Re: ponteiro char

Paulo
paulo1205

(usa Ubuntu)

Enviado em 27/06/2013 - 11:41h

uilianries escreveu:

Resolva assim:


const char * s = {"Andre"};



Só não precisa dessas chaves (i.e. basta fazer const char *s="Andre";).

Aliás, note que a declaração acima é um ponteiro para caracteres constantes. Isso significa que a string não pode mudar, mas você ainda pode fazer com que s aponte para outro lugar. Ou seja, é perfeitamente válido fazer o seguinte.

#include <iostream>
#include <iomanip>

int main(){
const char *s="Teste";
std::cout << "Conteudo de " << static_cast<const void *>(s) << " em diante: " << s << '\n';
s=new char[20];
std::cout << std::hex << std::setw(2) << std::setfill('0') << std::showbase;
for(int i=0; i<20; i++){
std::cout << "Conteudo de " << static_cast<const void *>(s+i) << ": " << static_cast<int>(s[i]);
if(isprint(s[i]))
std::cout << " ('" << *s << "')";
std::cout << '\n';
}
s="Paulo";
std::cout << "Conteudo de " << static_cast<const void *>(s) << " em diante: " << s << '\n';
return 0;
}


Se você quiser que, além de não poder alterar o conteúdo, o ponteiro também não possa apontar para outro objeto, você pode declarar o ponteiro como constante.

char *pc; // ponteiro variável para caracteres variáveis
const char *pcc; // ponteiro variável para caracteres constantes
char *const cpc; // ponteiro constante para caracteres variáveis
const char *const cpcc; // ponteiro constante para caracteres constantes


No caso específico de C-strings, voce pode usar a sintaxe de declaração de strings através de arrays.

char str[]="Paulo";         // string com seis caracteres (5 letras + byte nulo)
const char cstr[]="Paulo"; // string constante com seis caracteres

str[0]='S'; // Agora a string contém "Saulo".
cstr[0]='S'; // Erro de compilação: esta string é constante.



4. Re: ponteiro char

fiewhifwe
henriquemh

(usa Ubuntu)

Enviado em 27/06/2013 - 13:47h

Tipo eu estou usando Linux, ai não deu certo, mais fui testar no Dev, e la compilo sem nenhum problema


5. Re: ponteiro char

fiewhifwe
henriquemh

(usa Ubuntu)

Enviado em 27/06/2013 - 15:44h

deu certo do jeito que eu fiz e o MALDITO copilador g++ que ta me zoando
compilei com gcc e deu certo


6. Re: ponteiro char

Paulo
paulo1205

(usa Ubuntu)

Enviado em 27/06/2013 - 16:43h

Porque o compilador do Dev-C++ é velho, não atendendo ao padrão do C++. Antigamente essa construção de atribuir uma constante literal a um ponteiro não qualificado com const, que ainda funciona em C, funcionava também na maioria das implementações pré-padrão do C++.

Se você atualizar o compilador usado pelo Dev-C++ (deve dar para fazer isso de alguma forma, afinal o Dev-C++ é só um front-end para o GCC) provavelmente vai ter os mesmos erros.

Veja porém que a forma de corrigir é fazer o ponteiro ser mesmo um ponteiro para dados constantes. Mesmo em C, embora seja legal fazer a tal atribuição, é ilegal depois usar esse ponteiro para escrever na área atribuída, mas o compilador não tem como detectar isso nem lhe informar. Abaixo segue o extrato de uma sessão que demonstra isso de modo bem claro.

$ cat z.c
char str[]="Teste";
char *s="Saulo";

int main(void){
str[0]='P';
s[0]=str[0];
return 0;
}


O programa é bem simples: declara um array (não constante) e um ponteiro para dados não constantes s, mas que é feito apontar para uma constante, e depois tenta alterar os primeiros elementos do array e do ponteiro.

$ gcc -Wall -Werror -O2 -std=c99 -pedantic -g z.c -o z 


Compila-se o programa com o máximo de opções de diagnósticos ligadas, e também com opções para embutir no código executável informações de depuração. Mesmo com todas as opções de diagnóstico, não vem nenhuma mensagem de erro.

Apesar da diferença intrínseca de tipos de dados entre o ponteiro para dados não-constante e a constante para a qual ele aponta, o padrão do C determina -- por questões de compatibilidade com código antigo -- que tal tipo de atribuição deve ser aceita no caso específico de constantes strings. Então essa atribuição não provoca reclamação.

A linha seguinte (s[0]=str[0];) também não pode provocar reclamação, já que é perfeitamente válido mudar um dado apontado por um ponteiro que não é qualificado como constante.

$ ./z
Segmentation fault (core dumped)


O programa é executado, mas dá pau (falha de segmentação, que geralmente indica acesso ilegal à memória). Uma cópia da memória no momento da falha é gravada no arquivo "core".

$ echo bt | gdb z core
GNU gdb (Ubuntu/Linaro 7.4-2012.02-0ubuntu2) 7.4-2012.02
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /tmp/tmp/z...done.
[New LWP 8262]

warning: Can't read pathname for load map: Input/output error.
Core was generated by `./z'.
Program terminated with signal 11, Segmentation fault.
#0 main () at z.c:6
6 s[0]=str[0];
(gdb) #0 main () at z.c:6
(gdb) quit


Para ver exatamente onde deu pau, chama-se o depurador (gdb) sobre o programa z, pedindo que ele use como imagem de memória o arquivo core, gerado acima. Passa-se ao gdb o comando "bt", que faz com que ele imprima um back-trace da execução.

Veja na saída do gdb que ele realmente indica que o programa saiu com um o sinal 11 (SIGSEGV), e na impressão do back-trace aponta-se justamente a linha em que se tenta alterar o primeiro caráter da string. Por quê?

$ objdump -j .data -j .rodata -s z

z: file format elf64-x86-64

Contents of section .rodata:
4005b8 01000200 5361756c 6f00 ....Saulo.
Contents of section .data:
601008 00000000 00000000 00000000 00000000 ................
601018 bc054000 00000000 54657374 65000000 ..@.....Teste...


Roda-se o comando objdump, pedindo-se que ele imprima o conteúdo das seções ".rodata" (de read-only data), bem como ".data" (dados comuns, com acesso de escrita). Veja onde está cada uma das strings.

Por que "Saulo" está como read-only, e "Teste" como dado alterável? Porque "Teste" é parte da definição de um array, dispondo seus seis bytes (cinco letras mais o byte nulo) ao longo da memória alocada específicamente para aquele array. E como o array não é declarado como constante, então seu conteúdo deve ser disposto numa região de memória que possa ser modificada (se ele fosso constante, também iria parar em ".rodata").

Já os seis bytes de "Saulo" (também cinco letras mais o byte nulo) são uma constante literal do programa. s é uma variável de tipo ponteiro, que pode, ao longo do programa, apontar para qualquer lugar. Seu vínculo com a constante "Saulo" é, do ponto de vista do compilador, apenas uma situação casual.

Mas por que o compilador insiste que uma constante literal seja marcada como read-only?

Além da resposta óbvia embutida na palavra "constante", existem motivos de ordem prática para tanto. Uma possibilidade de implementação --que, de fato, a maioria dos compiladores pratica -- é identificar constantes repetidas ao longo do programa, e eventualmente fazer com que elas apontem para a mesma região de memória. Numa implementação assim, alterar uma das constantes possívelmente faria com que todas as outras constantes idênticas fossem também alteradas, mesmo sem que isso fique explícito para o usuário.

Veja o seguinte programa.

#include <stdio.h>

int main(void){
char *s="Saulo";
s[0]='P';
printf("%s\n", s);
printf("%s\n", "Saulo");
return 0;
}


Ele vai compilar, mas não vai rodar. O que me interessa é a saída do objdump, para demonstrar que o compilador aglutinou as quatro strings em apenas duas.

objdump -s -j .rodata -j .data x

x: file format elf64-x86-64

Contents of section .rodata:
400658 01000200 5361756c 6f002573 0a00 ....Saulo.%s..
Contents of section .data:
601010 00000000 00000000 00000000 00000000 ................


Veja o que vai acontecer se eu embutir no programa um código de baixo nível que altera as permissões do segmento onde está contida a string "Saulo", de modo a habilitar nela a possibilidade de alterá-la.

$ cat x.c
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/mman.h>

char *s="Saulo";

int main(void){
size_t pg_size=sysconf(_SC_PAGE_SIZE);
void *pg_start=(void *)((long)s & ~(pg_size-1));
mprotect(pg_start, pg_size, PROT_READ|PROT_WRITE|PROT_EXEC);

s[0]='P';
printf("%s\n", s);
printf("%s\n", "Saulo");
return 0;
}

$ gcc -Wall -Werror -std=c99 -pedantic -O2 x.c -o x

$ objdump -s -j .rodata x

x: file format elf64-x86-64

Contents of section .rodata:
400708 01000200 25730a00 5361756c 6f00 ....%s..Saulo.

$ ./x
Paulo
Paulo


Ou seja, forçar a mão para alterar uma string referida (temporariamente!) por uma variável ponteiro acabou alterando outra string que é uma constante do programa.


7. Re: ponteiro char

Paulo
paulo1205

(usa Ubuntu)

Enviado em 27/06/2013 - 18:59h

henriquemh escreveu:

deu certo do jeito que eu fiz e o MALDITO copilador g++ que ta me zoando
compilei com gcc e deu certo


"Zoando" nada. Se o seu compilador lhe der uma mensagem, confie nela.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts