Ir para o conteúdo
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

PsySc0rpi0n

Programa com strings

Mensagens Recomendadas

PsySc0rpi0n

Comecei a aprender as strings e estava a tentar criar um programa que pedisse ao user uma frase e que em todas as letras acentuadas ou acedilhadas ele colocasse um cardinal... Ou seja;

Lê uma frase

Copia a frase para outra variável para guardar a original

Procura vogais acentuadas

Substitui-as por #'s

Apresenta a frase original e a frase alterada...

O code que tenho é este mas não está a funiconar

#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main (void){
  char frasein [100], fraseout [100];
  int i;
  printf ("Introduza uma frase: ");
  gets (frasein);
  for (i=0; i<strlen (frasein); i++)
	fraseout [i] = frasein [i];
  for (i=0; i< strlen (fraseout); i++)
	switch (tolower (fraseout [i])) {
		   case 'ç':
		   case 'â':
		   case 'ã':
		   case 'á':
		   case 'à':
		   case 'é':
		   case 'è':
		   case 'ê':
		   case 'í':
		   case 'ì':
		   case 'ó':
		   case 'ò':
		   case 'ú':
		   case 'ù':fraseout [i] = '#';
	}
  printf ("Frase original: %s!!!\nFrase final: %s!!!\n", frasein, fraseout);
getchar ();
return 0;
}

O que é que está mal para ele não fazer o pretendido?

Editado por PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

É que com o seguinte código funcionou e com este que criei já não está a dar...

Código que funcionou:

#include <stdio.h>
#include <ctype.h>
#include <string.h>

int main (void) {
int i, comp;
char frasein [100], fraseout [100];

printf ("Digite uma frase: ");
gets (frasein);
comp = strlen (frasein);

for (i=0; i<comp; i++)
 switch (tolower (frasein [i])) {
  case 'a':
  case 'e':
  case 'i':
  case 'o':
  case 'u': frasein [i] = '#';
}
printf ("Frase digitada: %s\n", frasein);
getchar ();
return 0;
}

Editado por PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

Suponho que as diferenças estejam no charset usado pelo compilador e pelo ambiente de execução do programa.

Executa este programeta para verificar:

#include
int main(void) {
char buffer[100];
printf("Introduz a string 'ãéç':");
fgets(buffer, sizeof buffer, stdin);
printf("input do teclado: %d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("valores compilados; %d %d %d\n", 'ã', 'é', 'ç');
   return 0;
}

A melhor solução é veres os valores resultantes de teclado para cada letra e usar esses valores nos cases do switch.

Usa o valor directamente

			 case 183: /* ... */


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Aqui o #inlcude sem nada à frente dá erro...

Output do teu programa:

Introduz a string 'ãéç':ãéç

input do teclado: -61 -93 -61

valores compilados; 50083 50089 50087

Editado por PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

Aqui o #inlcude sem nada à frente dá erro...

Output do teu programa:

Oops, isso foi uma desatenção minha. O meu computador teve um BSOD quando eu estava a escrever o programa; depois do reboot fiz a recuperação da resposta mas falhou o include.

Era suposto ser

#include <stdio.h>

O programa continua a não dar output com o include correcto?


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

O teu dá

Introduz a string 'ãéç':ãéç

input do teclado: -61 -93 -61

valores compilados; 50083 50089 50087

Para explicar melhor...

O programa que está a funcionar bem, foi escrito, compilado e executado num telefone Android (linux based).

O programa que não me está a funcionar foi escrito, compilado e executado num PC com Debian mas estou a aaceder a esse PC através de um PC com Windows XP através do putty...

Não sei se me fiz entender... Será que isto faz diferença?


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

Então a minha suposição é verdade: o charset de execução e o charset de compilação são diferentes.

Usa os valores obtidos com o charset de execução no código do teu programa:

                           // ...
                          case -61:
                          case -93:
                          case -61:fraseout [i] = '#';

Este problema acontece porque o C básico foi pensado para caracteres ASCII e os caracteres 'ç', 'é', etc não são ASCII. O uso de caracteres que não são ASCII em regras diferentes consoante o ambiente em que estão a ser usadaos.

Por exemplo: no editor o 'ã' tem o valor 50083, no cmd.exe o 'ã' tem o valor -61.


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Eu pensei que todos os caracteres tinham um code ASCII igual fosse qual fosse a plataforma em que os programas fossem compilados...

Eu ainda não percebo nada disso dos charsets afectos ao SO ou ao ambiente em que estão a ser ocmpilados (compiladores)...

Mas a prof da cadeira escreveu o tal programa que está a funcionar, em Windows e eu copiei o code para o meu telefone (Android) e funcionou bem!!! Por isso não consig compreender isso... E os profs também não sabem explicar porque eles só estão habituados ao Windows e ao Visual Studio Express e pouco mais...

Eu, em termos de programação, eu só estou habituado praticamente ao Linux, ou seja, GCC e também um pouco ao Code::Blocks no Windows...

PS:

Falas que no editor o 'ã' tem um valor e que no cmd.exe tem outro.

Em que editor falas? cmd.exe presumo que seja windows, certo?

Editado por PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

Os caracteres básicos (letras maisuculas e minusculas sem acentos, digitos, muitos sinais de pontuacao) tem o mesmo valor em praticamente todos os computadores existentes actualmente (ASCII).

Para os caracteres fora desse conjunto (letras com acentos, caracteres gregos, caracteres japoneses, simbolos variados, ..., ...) ha muitas maneiras diferentes de os representar numericamente.

Se o teu editor e o teu ambiente de execução representarem os caracteres com o mesmo valor numérico, é mais fácil acertar o que está escrito no código e o que aparece quando se corre o programa; se o editor e o ambiente de execução usam valores numéricos diferentes estás metido numa salganhada diabólica.

Para principiantes (e programas de aprendizagem) é aconselhável ignorar estes problemas e usar somente os caracteres basicos.

Se o assnto te interessa podes ler (pesquisa google) sobre os tópicos DBCS, Unicode, EBCDIC, code page, endianness, ...


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Voltando a esta questão...

Como faço então para saber a que código corresponde um 'é' ou um 'ç' no meu PC?

Depois de saber esses valores, uso-os no switch, não era isso que querias dizer, pmg?


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Escrvi isto a ver se funcionava bem para me retribuir os valores destes caracteres ams não ficou a funcionar muito bem...

Deve ainda ali haver algum problema com o buffer do teclado que não o sei resolver...

#include <stdio.h>
int main (void){
  int i, e;
  char car;
  for (i=1; ; i++){
  printf ("Para sair, digite \'0\'\n");
  scanf ("%d", &e);
  if (e){
	 printf ("Introduza um caracter para avaliar: \n");
	 scanf (" %c", &car);
	 printf ("O caracter inserido %c tem o valor de %d\n", car, (int) car);
  }
  else
	 break;
  }
getchar ();
return 0;
}


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

usa o seguinte código para perceber o que se passa e o que deverás fazer

#include <stdio.h>
#include <string.h>
#include <wchar.h>

#define IS_MB_CHAR(a) (a >= 128)
#define IS_MB_CHAR_PT(pt) (*pt >= 128)

const char * to_binary(int x, int size)
{
   static char b[33] = {0};
   int z;

   for (z = size * 8 - 1; z >= 0; z--)
   {
       b[z] = (x & 1) + '0';
       x >>= 1;
   }

   return b;
}

int in_list(unsigned char * c, const char * list)
{
   int length = strlen(list) - 1;
   int i = 0, size = 1;

   if (IS_MB_CHAR_PT(c))
       size = 2;

   for (i = 0; i < length; i++)
       if (memcmp(c, &list[i], size) == 0)
           return 1;

   return 0;
}

int main()
{
   char readed[100] = {0};
   char accents[86] = "áàãâÁÁÃÃéèẽêÉÈẼÊíìĩîÍÌĨÎóòõôÓÒÕÔúùũûÚÙŨÛçÇ";
   int i, pos, is_accent;

   printf("digite a string : ");
   fflush(stdout);
   fgets(readed, 20, stdin);
   readed[strlen(readed) - 1] = 0;
/*
   printf("input : ");
   for (i = 0; readed[i] != 0; i++)
     printf("%s|", to_binary(readed[i], sizeof(char)));
   printf("\n");
*/

   for (i = 0, pos = 0; readed[i] != 0; i++, pos++)
   {
       is_accent = in_list(&readed[i], accents);
       printf("Caracter %2d (%2d=%c) is acentuated : %d\n",
              pos,
              i,
              !is_accent ? readed[i] : '#',
              is_accent);

       if (is_accent)
           i++;
   }

   return 0;
}

Editado por HappyHippyHippo

IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

Um ciclo infinito (que acaba com um break) feito com for é assim

for (; { /* codigo com um break algures */ }

Ja agora, podes fazer um ciclo infinito com while ou do /* ... */ while

while (1) { /* codigo com um break algures */ }

do { /* codigo com um break algures */ } while (1);

~~~~~~~~

Quanto a solucao para o teu problema da identificacao de caracteres, a minha primeira solucao é incompleta (nao funciona para conjuntos de caracteres com multi-byte) e provavelmente nao funciona para ti. Experimenta a sugestao do Hippo.


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

O output do gcc a compilar é:

hippyhippo.c: In function ‘main’:
hippyhippo.c:56:23: warning: pointer targets in passing argument 1 of ‘in_list’ differ in signedness [-Wpointer-sign]
hippyhippo.c:22:5: note: expected ‘unsigned char *’ but argument is of type ‘char *’

O programa deu o seguinte quando executado:

./hippyhippo

digite a string : Os cães apenas são perigosos se os donos forem deveras otários!

Caracter 0 ( 0=O) is acentuated : 0

Caracter 1 ( 1=s) is acentuated : 0

Caracter 2 ( 2= ) is acentuated : 0

Caracter 3 ( 3=c) is acentuated : 0

Caracter 4 ( 4=#) is acentuated : 1

Caracter 5 ( 6=e) is acentuated : 0

Caracter 6 ( 7=s) is acentuated : 0

Caracter 7 ( 8= ) is acentuated : 0

Caracter 8 ( 9=a) is acentuated : 0

Caracter 9 (10=p) is acentuated : 0

Caracter 10 (11=e) is acentuated : 0

Caracter 11 (12=n) is acentuated : 0

Caracter 12 (13=a) is acentuated : 0

Caracter 13 (14=s) is acentuated : 0

Caracter 14 (15= ) is acentuated : 0

Caracter 15 (16=s) is acentuated : 0

Caracter 16 (17=▒) is acentuated : 0


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

a razão está no limite de caracteres dados na função fgets:

#define BUFFER_SIZE 256

// ...

int main()
{
   char readed[bUFFER_SIZE] = {0};

   // ...

   fgets(readed, BUFFER_SIZE, stdin);

   // ...
}


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Não percebi... Então o que tenho/devo/posso fazer para contornar o problema?


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

tens um output com metade da informação escrita, o problema é que estás a ler poucos dados do buffer de leitura (o meu código)

o que te disse foi para aumentares a memória usada para guardar os dados lidos do buffer de leitura


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Aumentar a memória usada para guardar os dados lidos do buffer de leitura é declarar uma variável tipo 'frasein [200]' em vez de 'frasin [100]' no meu código??

Editado por PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

Aumentar a memória usada para guardar os dados lidos do buffer de leitura é declarar uma variável tipo 'frasein [200]' em vez de 'frasin [100]' no meu código??

a razão está no limite de caracteres dados na função fgets:

#define BUFFER_SIZE 256

// ...

int main()
{
   char readed[bUFFER_SIZE] = {0};

   // ...

   fgets(readed, BUFFER_SIZE, stdin);

   // ...
}


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Eu não sei usar essas funções ainda... (fgets e companhia) por isso não posso entender o que fez esse teu code e não posso entender o que me estás a tentar dizer se não explicares de forma a que eu possa entender, ou seja, tendo em conta os meus conhecimentos...

O teu code tem várias coisas que eu não conheço, como por exemplo:

1 - os dois pares de parêntesis a seguir à declaração das variáveis constantes IS_MB_CHAR e IS_MB_CHAR_PT.

2 - Isto, const char * to_binary(int x, int size), apenas percebo que é uma função mas não a entendo porque é uma função que é um ponteiro????...

3 - static char b[33] = {0}; Isto, segundo sei, é um vector que na posição 33 tem o valor zero mas não sei o porquê deste valor nem o porquê de dizer static antes do tipo de variável...

4 - Não percebo estes dois comandos

b[z] = (x & 1) + '0'; --> b[z] toma o valor de x concatenado com 1 + o caracter zero???????

x >>= 1; --> Conheço este símbolo da consola do linux que faz o append. Não sei o que faz aqui neste caso com o igual a seguir.

5 - Percebo isto

if (IS_MB_CHAR_PT(c))

size = 2;

mas não sei qual é o objectivo disto no programa.

6 - if (memcmp(c, &list[ i], size) == 0) - não sei o que é o memcmp? É uma função de alguma library? Se não é, onde está declarada esta função?


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo
Em 1/10/2013 às 10:05, PsySc0rpi0n disse:

1 - os dois pares de parêntesis a seguir à declaração das variáveis constantes IS_MB_CHAR e IS_MB_CHAR_PT.

o que está definido é uma função macro.

da mesma forma que podes ter:

#define MAX (256-10)
printf("%d\n", MAX); // <-- "MAX" irá ser substituído por "(256-10)" pelo pré-compilador
podes ter para algo com o aspecto de funções:
#define MAX(a, b) (a > b ? a : b)
printf("max : %d\n", MAX(10, 23)); // <-- "MAX(10, 23)" irá ser substituído por "(10 > 23 ? 10 : 23)"
já agora, o que usei no exemplo for o operador ternário:
// <condição> ? <verdadeiro> : <falso>
    a > b    ?      a       :    b

// ou, porque podes usar o valor latente do resultado (verdadeiro/falso)

// variavel =  <condição> ? <verdadeiro> : <falso>
    var    =    a > b    ?      a       :    b
 
Em 1/10/2013 às 10:05, PsySc0rpi0n disse:

2 - Isto, const char * to_binary(int x, int size), apenas percebo que é uma função mas não a entendo porque é uma função que é um ponteiro????...

a função não é um ponteiro

a função retorna um ponteiro para uma região de memória a ser interpretada como um caracter.

o que a função retorna é na realidade uma string com 0's e 1's representativa do código binário do valor dado como primeiro argumento da função.

Em 1/10/2013 às 10:05, PsySc0rpi0n disse:

3 - static char b[33] = {0}; Isto, segundo sei, é um vector que na posição 33 tem o valor zero mas não sei o porquê deste valor nem o porquê de dizer static antes do tipo de variável...

não, é um vector com 33 posições inicializado todo a 0

está static, porque é o valor de retorno da função. caso não tivesse o static, no momento de retorno da função, a memória alocada na stack para o array era libertada e dava bronca.

desta forma garanto que mesmo após o retorno da função, a memória alocada para o array continua acessível.

Em 1/10/2013 às 10:05, PsySc0rpi0n disse:

4 - Não percebo estes dois comandos

b[z] = (x & 1) + '0'; --> b[z] toma o valor de x concatenado com 1 + o caracter zero?

x >>= 1; --> Conheço este símbolo da consola do linux que faz o append. Não sei o que faz aqui neste caso com o igual a seguir.

isso são os comandos dentro do ciclo.

a intenção é de popular o array "b" com 0's e 1's criando a representação textual do binário do número dado.

a primeira instrução, é guardar na posição "z" (valor que é iterado no ciclo) o resultado de:

(x & 1) + '0'

por partes:

x & 1 é a comparação bit a bit do primeiro argumento (x) com o valor de 1, número que é representado com tudo a zeros menos no bit menos significativo. em 8 bits seria:

 10100100
& 00000001
----------
 00000000 (1 se forem os dois 1 ou 0 caso contrário)
ficas então com 1 ou com 0 dependendo do valor de x tiver 1 ou 0 no bit menos significativo.

depois adicionas 1 ou 0 ao valor de '0' ficando com o caracter '0' ou '1' respectivamente.

desta forma crias a representação textual de um bit

---

o segundo comando é um right-shift-logical que move todos os bits de um número X vezes para a direita, em 8 bits seria

numero : 01001001

(left-shift-logical de 3 casas) = 00001001|001
                              resultado  |  descartado
como o operador que usei foi com 1, então em cada ciclo da iteração, está a mover todos os bits do numero 1 casa para a direita. desta forma consigo ler sempre o bit menos significativo do numero a ser lido.
Em 1/10/2013 às 10:05, PsySc0rpi0n disse:

5 - Percebo isto

if (IS_MB_CHAR_PT( c))

size = 2;

mas não sei qual é o objectivo disto no programa.

os caracteres "convencionais" são codificados entro o valor de 0 e 127.

no entanto, já verificaste que isso é completamente insuficiente para representar todos os caracteres existentes.

é por isso que todos os caracteres que se situam na gama 128-255 são representativos de um caracter que necessita de 2 bytes para ser codificado.

o que acontece é que para codificar um caracter acentuado (e outros), necessitas então de dois caracteres. um que te dita uma gama e um segundo que especifica qual caracter dentro dessa gama.

como foi explicado no primeiro ponto, é usada uma função macro para verificar se o caracter é de dois bytes e não de um (c > 127)

se sim, o tamanho (size) é de 2 bytes e não de 1

Em 1/10/2013 às 10:05, PsySc0rpi0n disse:

6 - if (memcmp(c, &list[ i ], size) == 0) - não sei o que é o memcmp? É uma função de alguma library? Se não é, onde está declarada esta função?

é de uma biblioteca, a que usas a toda a hora : libc.

a libc tem muito mais do que sabes neste momento, assim como printf, scanf, fgets, malloc, free, etc, etc ...

é uma grande quantidade de funções que é ensinado/apresentado aos pouco, se bem que a taxa de utilização das funcionalidade é bem centrada num par de dúzias delas.

as pessoas que é que se esquecem que esta biblioteca

o memcmp é uma função que se encontra declarada no header string.h ou mesmo no memory.h (se bem que o segundo é redundante).

a função compara dois blocos de memória de tamanho X, e retorna 0 se forem iguais ou diferente de zero caso contrário.

conclusão, estou a comparar os bytes em memória, usando o tamanho definido pelo tipo de caracter (1 byte ou 2 bytes)


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Pois... Como já esperava, não tenho conhecimentos para poder entender bem a tua explicação que me parece absolutamente explícita...

Já consegui perceber melhor algumas partes da tua epxlicação, nomeadamente das funções macro.

O resto acho que nem vou pedir agora para explicar porque não iria resultar, pois preciso de mais conhecimentos para poder entender...

Não tenho grandes conhecimentos ao nível da memória do PC, nem de como funciona ao certo e muito menos de saber interpretar código binário.

As libraries já eu tenho noção que são um mundo de extensões que permitem que os programas sejam muito mais dinâmicos que o que seriam sem elas mas não, não faço ideia do que está dentro dessa library libc, nem dentro de muitas outras que devem existir...

Vou guardar esta thread para mais tarde consultar quando entender melhor estas matérias...

Obrigado na mesma...


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.