Ir ao conteúdo
  • Cadastre-se

C - atribuição de strings a partir de uma entrada


Philipe de Souza
Ir à solução Resolvido por vangodp,

Posts recomendados

Bom dia pessoal,

 

estou com uma dúvida que parece ser bem simples mas ainda não descobri como fazer.

 

Por exemplo, no meu programa o usuário vai ter que dar a seguinte instrução de entrada:

 

Siga norte a partir da Avenida NS da Penha 1600

 

Eu preciso que "norte" seja atribuído a uma string nomeada de direção, 

preciso que "Avenida NS da Penha" seja atribuída a uma string nomeada de rua,

e por final, preciso que "1600" seja atribuída a um inteiro nomeado de num. 

 

Isso sem ter que digitar um por um, pausadamente, o programa precisa que capture essas informações e as atribua as variáveis.

 

Como faço isso?

 

Agradeço desde já!

Link para o comentário
Compartilhar em outros sites

  • Solução
#include<stdio.h>

int main(){
    char dir[100];
    char rua[200];
    int num;
    char * frase = "Siga norte a partir da Avenida NS da Penha 1600";
    
    
    sscanf(frase, "%*s %s %*c %*s %*s %[^0-9]s %d", dir, rua, &num );
    printf("Direcao: %s \nRua: %s \nNum: %d \n\n", dir, rua, num);
    return 0;
}



scanf/sscanf/fscanf/etc lê uma string até encontrar um dos seguintes chars: ' ', '\t', '\n'. É dizer que si temos que ler algo com nome, e sobre nome, algo como "Pedro Alcantra", se tentar ler  isso com scanf por exemplo, e querer guardar em uma variável como char nomeCompleto[100], você tem que fazer algo como scanf("%s", nomeCompleto). porém logo depois de entrar com a string "Pedro Alcantra" e imprimir nomeCompleto você vai se dar conta que somente LEU "Pedro". Ué! Onde tá o Alcantra? Ficou no buffer! Por quê? Porque como falei, o scanf só lê ate encontrar espaço(' '), tabulador('\t') ou até encontrar enter('\n'), e justamente depois do "Pedro" tem um espaço(Entre "Pedro" e "Alcantra" temos ' '). O programa Lê Pedro e o resto fica no buffer de entrada(stdin) esperando uma nova variável para entrar.
Se você fizer algo como:
char nome[100];
char sobrenome[100];

e logo depois fizer:
scanf("%s", nome);

scanf("%s", sobrenome);

Na hora que o programa esperar o nome você bota tudo ai no primeiro scanf "Pedro Alcantra".
Adivinha o que vai acontecer? >_< Tenta imprimir...o pedro vai parar no nome e o alcantra vai parar no sobrenome.

A explicação é que quando você ta escrevendo no teclado, tudo o que você ta escrevendo vai acumulando no buffer de entrada. Não vai parar de acumular até que o programa detecte que você pulsou enter('\n'). O enter também é considerado uma letra, e entra junto no buffer, mas depois de pulsar enter "começa a soltar lastre". >_<

Depois de pulsar enter o scanf começa retirar letra por letra do buffer stdin, ele vai jogando na primeira variável que apareceu, essa é nome. Ele vai fazer isso até quando? Até encontrar espaço(' '), tabulador('\t') ou até encontrar enter('\n') omi!! :lol:

Adivinha o que o scanf vai encontrar primeiro na sua frase? O espaço que está logo depois de "Pedro", dai como falei antes, ele para de jogar letras na "variável do momento", o restante fica no buffer.

porém quando pulsamos enter, depois de entrar com uma frase como "Pedro Alcantra", a ordem é "Tira tudo fora!", o buffer tem quer ser esvaziado completamente. Se você botar outro scanf em seguida, o programa vai pegar o resto do que ta no buffer e vai jogar ele na seguinte variável que aparecer, mesmo esta estando em outro escanf, "MAS SÓ SE O TIPO DE VARIÁVEL COINCIDE COM O QUE FICOU NO BUFFER".

Se você ler usar 2 strings consecutivos, o resto que permanecer no buffer depois que o primeiro scanf encontrar dessas três letras, se descarrega no segundo string, mas se aparecer uma variável de outro tipo diferente isso não vai acontecer. Isso só acontece se você ler ou 2 ou mais strings consecutivos, 2 ou mais chars consecutivos, ou você ler um char e um string logo depois... esse é um caso bastante especial. É especial porque a letra vai parar no primeiro char que aparecer, e o que vai parar no string é o enter(WTF!), causando vários erros na leitura.

Se você não souber lidar com os problemas anteriores, certamente vão lhe causar muitos problemas. Isso acontece por que em C, se o programa ta esperando uma palavra e você escrever um simples char, ele aceita, então imagine que você tem que ler um char e depois um string, você entra uma letra como 'a' e pulsa enter, enter também é uma letra(igual que os outros chars e todo o resto sa tabela asc2), dai o que acontece é que você tem 2 chars pelo preço de 1. Os tipos coincidem perfeitamente, 'a' vai parar no primeiro char, e como falei antes uma letra(enter) pode entrar em um string, o resultado é um programa fora de controle. No fundo a culpa é do programador por não saber usar scanf+buffer corretamente, certamente por desinformação.

Bom... agora que ja sabe um "pouquinho" mais( -_-' )  sobre o funcionamento do buffer + essas funções de entrada como scanf, sscanf e fscanf. Deixo claro que são todas mais ou menos iguais só que o scanf lê o string desde o buffer stdin, sscanf lê desde outra string, e fscanf lê desde um arquivo, mas todas leem desde outras strings....

Vamos com a explicação disto: sscanf(frase, "%*s %s %*s %*s %*s %20[^0-9] %d", dir, rua, &num );

sscanf lê desde frase. O primeiro parâmetro é a string frase na qual contêm a frase"Siga norte a partir da Avenida NS da Penha 1600".
O segundo parametro é clave nessa historia, pois é ele que vai determinar o comportamento do scanf: "%*s %s %*s %*s %*s %20[^0-9] %d". Vamos com a explicação sobre o segundo parâmetro.
Como sabemos temos a frase "Siga norte a partir da Avenida NS da Penha 1600". O primeiro especificador(%*s) é o contrario de %s. Se %s permite ler um string, e o joga em uma variável do tipo char[], %*s ignora por completo a primeira string que aparece. Ou seja... a primeira palavra na frase vai ser ignorada respeitando as regras que suamos antes para entender :mellow:. A palavra "Siga" será ignorado pelo primeiro especificador até encontrar um daqueles 3 chars "ixpertinhos" que falamos antes, nesse caso até o espaço que vem logo depois de "Siga".

Como %*s é o inverso de %s e ignora uma palavra, não precisamos passar nenhum argumento para a função, em outras palavras, só precisamos passar argumentos quando vemos %s, %d, %c, se vemos seus antagonistas(%*s, %*d, %*c) quer dizer que não temos que passar variáveis ok. O asterisco( * ) no meio de um especificador a essa altura acho que você ja deduziu o que faz... "ignora a leitura da variável".

Como temos de frase "Siga norte a partir da Avenida NS da Penha 1600", %*s ignora "Siga".

Agora nos situamos em "norte". Essa sim você quer jogar ela em uma variável chamada "direcao" certo? Trata-se de um string... então teríamos que usar algo como char direcao[100]. Dessa vez você está obrigado a passar o argumento no terceiro parâmetro de sscanf, que é nossa variável, pois não estamos ignorando nada, dessa vez vai haver leitura.

Então agora %s lê "norte" e joga isso em dir(no meu caso). Agora nos situamos antes da 'a'. Lembre que 'a' também é um string se está dentro de outro string, então posso lhe ignorar tanto com %*s como com %*c, por conveniência eu usei %*s. Então os seguintes 3 especificadores %*s ignoram 3 palavras, ou seja "%*s %*s %*s" ignora a "a partir da".

Agora ja chegamos adiante do nome da rua, heis aqui un problema.
O problema que temos agora é que você quer jogar "Avenida NS da Penha" em uma só string e como falei o scanf tem aquele peculiar comportamento de tropeçar com as 3 variáveis que falei. porém não tudo está perdido...

Existe um especificador que é algo mais complexo(mas nem tanto), que nos permite tragar tudo até onde queremos. Esse especificador é o %[algo]s onde "algo" é um conjunto de regras que serão respeitados na hora de ler as seguintes letras.

No caso de %[^0-9]s, o primeiro a explicar é que quando o programa vê %[]s, ele vai ler atropelando tudo por adiante, incluindo espaços, tabuladores, tecla enter e o raio que o parta >_<. Dai a necessidade de dizer pro caboclo que não('^') queremos números de 0 a 9(0-9).

Então %[^0-9]s quer dizer que comece ler desde "Avenida" até encontrar um numero qualquer de 0 a 9, si tiramos o ^(chapéu) quer dizer o contrario, que o especificador vai ler só números de 0 a 9, se encontrar um desses números passa ao seguinte especificador, e se não tiver mais nenhum sai do scanf. Com chapéu ele ignora.

Isso aí é tema delicado, mas esse especificador %[]s é a coisa mais maravilhosa do mundo >_<.
Alguns exemplos:
scanf("%[BANGLADESH]", s);
Só lê a palavra "BANGLADESH" se falhar sai fora do scanf, s é um string.

scanf("%[^\n]", s);
Le tropelando tudo até que o usuari pulse o enter. A diferença é que essa versão sim le algo como "Pedro Alcantra" e joga tudo em um só string ignorando os espaços.

scanf("%d%*c%d", &h, &m);
Para ler hora tipo 10:30. Tambem funciona:
scanf("%d:%d", &h, &m);
Nesse caso os os 2 pontos no caso do scanf quer dizer que ignore 2 pontos que pode aparecer entre 2 inteiros, é dizer que pega "10:30" e joga o 10 em h e 30 em m ignorando o : .

scanf("%10s", s);
s vai conter máximo 9 letras + \0 = 10 letras. Muito util si você tem "char s[10]" e não quer superar o tamanho do string s. O problema é que se você digitar 100 letras 10 vão a parar a s e o resto permanece no buffer, dai se você chamar outra string e não tevir espaço vou puxar sua orelha. kkk Melhor limpar o buffer antes de fazer um novo scanf.

%*[ ] // ignora um espaço
%10[ ] //ignora 10 espaços
%[^a] //lê até encontrar uma letra 'a'
%[^\0]s // lê até encontrar null. Bom para isso:

    char * frase = "Siga norte a partir da Avenida NS da Penha 1600";
    char s[100];
    sscanf(frase, "%[^\0]s", s);
    printf(s);

Copia tudo da frase a s ignorando tudo(espaços, tabuladores e teclas enter), até encontrar o null que indica o fim da frase. Bom para copiar um string completo a outro, se parece muito a strcpy >_<

Bom, ja está bem de exemplos, vamos continuar com o exemplo né... só que o único que restou foi ler o inteiro, e isso acho que ja não precisa de mais parlatório.
 

Cara.. pratique muito com tudo isso que lhe expliquei leia muito sobre o comportamento dessas funções, como funciona os buffers stdion e stdou etc. falou? =)





 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

vando, muitíssimo obrigado pela explicação, foi muito simples e intuitiva!

 

Agora consigo compreender bem melhor o funcionamento do scanf.

 

e se no caso, ao invés de pré-definir o conteúdo do ponteiro frase que atualmente é "Siga norte a partir da Avenida NS da Penha 1600", eu mesmo digitar o texto, como eu faria? 

adicionado 22 minutos depois

Não sei se é a forma mais apropriada, mas fiz assim:

int main()
{
    char direcao[100], rua[200];
    int num;
    char nome[100];
    Pilha* p = novaPilha();
    scanf("%[A-Z a-z 0-9",nome);
    char* frase = nome;
    sscanf(frase, "%*s %s %*c %*s %*s %[^0-9]s %d", direcao, rua, &num);
    printf("Direcao: %s \nRua: %s \nNum: %d \n\n", direcao, rua, num);
return 0;
}

 

Link para o comentário
Compartilhar em outros sites

recomendo o uso de char[], tipo char frase[]. Se quer juntar palavras você pode usar a função strcat  que permite você "enmendar" palavras para formar um frase. Entre aqui e veja um exemplo: http://www.cplusplus.com/reference/cstring/strcat/

 

Para ler uma frase completa basta fazer:
char nome[100];

scanf("%100[^\n]s%*c",nome);

Depois disso deveria ser feito uma limpeza do buffer.
Se quiser copiar um string em outro você tem que usar a função strcpy: www.cplusplus.com/reference/cstring/strcpy/

A diferença de strcpy e strcat é que strcpy borra o conteúdo da string de destino, e strcat vai ligando as strings no destino sem.

 

Busque no google "funções úteis para strings em C" Certamente você encontrará muitas coisinhas interessantes >_<.

Sorte! Não poderei responder perguntas nos próximos dias, vou de viagem, se tiver mais duvidas abra um novo tema e aguarde a ajuda de outros companheiros valeu. Espero ter ajudado, talvez estarei de volta dentro de uns 5, ou pode que mais dias. :thumbsup:

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Visitante
Este tópico está impedido de receber novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

 

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!