Ir para o conteúdo
JoaoSkate

[Dúvida] Leitura e partição de strings

Mensagens Recomendadas

JoaoSkate

Boas,

eu tenho um programa onde através da consola insiro uma string com espaços e numeros, por exemplo: AA BBB 11.

Sendo que essa string pode no maximo ter 10 carateres, o meu problema está em repartir a string em partes e usar cada uma dessas partes para diferentes fins:

char comando[10];

printf("Introduza o comando: ");
scanf("%s", comando);

printf("%s",comando);

sendo que eu posso alterar a ordem pelo que aparecem os números e as as letras, por exemplo:

AA BBB 11

ou

GG 1 XXXX

ou 1 AA

há sempre um espaço a separar cada conjunto de carateres, mas eu quero ler tudo como uma só string e depois usar as diversas partes sem os espaços.

um dos problemas com que me estou a deparar é com o facto de o %s ler apenas uma palavra ate encontrar um espaço, ao encontrar coloca um '/0' no vetor e acaba, eu queria que lesse uma 'frase'', já pensei em usar o gets() no entanto o gets emite sempre warings no compilador

Obrigado.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
JoaoSkate

obrigado, penso que o fgets já envolve apontadores, eu ainda não dei nas aulas, pelo que penso que este exercicio envolve outro método.

eu estou a tentar o seguinte:

char a;
char a1[4];
char a2[4];

printf("Introduza o comando:");
scanf("%c %s %s", &a,a1, a2);


printf("teste: %c \n",a);
printf("teste: %s \n",a1);
printf("teste: %s \n",a2);

supondo que afinal os comando que eu introduza na consola são sempre do seguinte tipo, POR EXEMPLO:

Y 1

X ZZZ 10

X NNN MMM

existe alguma forma de fazer com que quando o scanf me pede "coisas" ele encerre quando o utilizador prime enter na consola e guarda nas variaveis a informação inserida, isto é, por exemplo quando introduzo : Y 1, o Y vai ser guardado na variavel a, e o 1 na variável a1, o problema é que o programa/a consola fica sempre à espera que seja inserido um 3º valor para guardar na variavel a2. (nao sei se me fiz entender, isto é um pouco dificil de explicar)

Ou seja, resumidamente, existe alguma forma de fazer com que este scanf por vezes receba só duas variaveis outras vez só uma varial e outras vezes as 3 variaveis?

Editado por JoaoSkate

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

obrigado, penso que o fgets já envolve apontadores, eu ainda não dei nas aulas, pelo que penso que este exercicio envolve outro método.

envolve praticamente tantos apontadores como a função gets

#define LINE_MAX_SIZE 1024

char line[LINE_MAX_SIZE];
fgets(line, LINE_MAX_SIZE, stdin);

existe alguma forma de fazer com que quando o scanf me pede "coisas" ele encerre quando o utilizador prime enter na consola e guarda nas variaveis a informação inserida, isto é, por exemplo quando introduzo : Y 1, o Y vai ser guardado na variavel a, e o 1 na variável a1, o problema é que o programa/a consola fica sempre à espera que seja inserido um 3º valor para guardar na variavel a2. (nao sei se me fiz entender, isto é um pouco dificil de explicar)

Ou seja, resumidamente, existe alguma forma de fazer com que este scanf por vezes receba só duas variaveis outras vez só uma varial e outras vezes as 3 variaveis?

não


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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
JoaoSkate

okay certo,

eu estou a tentar agora da seguinte forma:

#include

int main()
{

char val1, val2[4], val3[4];


scanf("%c %[^ ] %s", &val1, val2, val3);

/* testando :*/

printf("%c\n",val1);
printf("%s\n",val2);
printf("%s\n",val3);

return 0;
}

o problema surge quando a linha introduzida na consola nao obedece ao seguinte formato: a bbb ccc

por exemplo se for neste formato: a bbb , já nao funciona :(

ou seja, se eu introduzir na consola a bbb, e der <enter> ele fica sempre à espera de um terceiro para guardar na val3. eu já pensei eu fazer tipo if val3[0] == '\n' então acaba , mas nao funcionou muito bem

Editado por JoaoSkate

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

como te foi dito : usa o fgets para ler a linha toda do buffer de entrada, depois, usa a função sscanf para interpretar a linha lida


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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
JoaoSkate

Bem eu tentei fazer ainda de outra maneira:

#include 
#include 
struct Valores
{
char v1;
char v2[4];
char v3[4];
};

int main()
{

struct Valores b;
printf("insira linha: ");
scanf("%c %s %[^'\n']*'\n'", &b.v1, b.v2, b.v3);

//para testar

printf("comando 1: %c\n",b.v1);
printf("comando 2: %s\n",b.v2);
printf("comando 3: %s\n",b.v3);
return 0;


}

parte do meu problema já esta resolvi, que era guardar as partes de uma linha completa por exemplo A BBB CCC, em diferentes variàveis, o preblema que me falta resolver é o deu por exemplo a linha completa inserida na consola apena receber o 1º elemento ou apenas o 1º e o 2º por exemplo, eu pretendo que ao ser 'dado' <enter> o programa fique apenas com os valores inseridos até entao e nao que fique à espera dos restantes (nao sei se me faço entender)

escrevi este código com base numa dúvida já colocada aqui no forum que voçe HappyHippo respondeu a um utilizador sobre o que significava :

%[^\n]\n

ao que voçe respondeu

" quer dizer : come tudo até encontrar um caracter especificado nesta lista" (que neste caso é o caracter '\n'.

o \n final quer dizer que após ter encontrado esse mesmo caracter na pesquisa anterior, lê-o também, descartando/removendo do stream lido"

No entanto entanto nao aconteçe o que eu esperava isto é quando primo <enter> (que penso que representa o \n), o programa continua à espera de mais...

foi por isso que alterei para:

%[^'\n']*'\n

pois como \n é um carater penso que tenho de colocar entre ' ', mas o resultado foi exatamente o mesmo.

se puder dar uma ajuda agradecia :)

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
JoaoSkate

Okay acho que estou quase a resolver o problema, mas algo me está a escapar, o que tenho agora é:

#include <stdio.h>
struct Valores
{
char v1;
char v2[4];
char v3[4];
};

int main()
{

struct Valores b;
printf("insira a linha: ");
scanf("%[^\n]c %[^\n]s %[^\n]\n", &b.v1, b.v2, b.v3);

printf("comando 1: %c\n",b.v1);
printf("comando 2: %s\n",b.v2);
printf("comando 3: %s\n",b.v3);
return 0;


}

eu sei que a linha que vai ser inserida na consola pode ter as seguinte formas (com um espaço entre cada <>):

- < 1 carater> <uma string><outra string> , ex: a bbb ccc

ou

- < 1 carater> <uma string> , ex: a bbb

ou

< 1 carater> ex: a

ou

< 1 carater> <uma string><um inteiro> ex: a bbb 100

ou

< 1 carater> <um inteiro> ,ex: a 1

problema: na consola quando insiro por exemplo: a bbb ccc

o resultado é:

insira linha: a bbb ccc //printf

comando 1: a

comando 2: bbb ccc // o resultado esperado aqui era apenas bbb (sem o espaço antes, e sem o ccc depois) comando 3: ccc // o resultado esperado aqui era apenas ccc(sem o espaço antes)

ou quando a linha inserida é do tipo ex: a 10

o output é o correto

insira linha: a bbb ccc

comando 1: a

comando 2:

comando 3: //excepto um carater estranho que aqui apareçe

Editado por JoaoSkate

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Eu como estou também a tenter aprender alguma coisa, vou deixar a minha sugestão... Atenção que não faço ideia se é funcional ou não:

1 - Ler toda a string com o fgets

2 - Usar o strstr e o strtok para extrair as 3 strings para 3 variáveis separadas ou para usá-las directamente.

Mas também são sei se percebi bem o que pretendes fazer. Se eu percebi, queres inserir 3 strings de tamanhos variáveis até um máximo de 10 caracteres, separadas por espaços e depois poder usar essas 3 strings separadamente. É isto?

Eu desses scape characters não percebo nada, mas pelo que vi no teu último code, no scanf não estás a ignorar os "new line" characters em vez dos espaços?

Depois acho que há outro problema no code:

o facto de poderes alterar a ordem dos dados porque depois vais estar a guardar dados nas variáveis de tipos de dados errados. Ou pelos menos, quando fizeres o printf das variáveis, podes estar a contar com a representação do "inteiro" 10 e ser imprimido o caractér ASCII correspondente ao inteiro 10. Não sei se consegues contornar facilmente este problema!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Flinger

O PsySc0rpi0n tem razão em todos os pontos.

Com o scanf tens de saber o pattern a ler de antemão. Isso vai completamente contra o que tu queres. O mais correcto é leres a string inteira primeiro (com o fgets por exemplo), e depois fazer o parse da string, com o sscanf, ou palavra a palavra, através do uso do strtok, como sugeriu o PsySc0rpi0n, ou mesmo caracter a caracter, se não quiseres/não estiveres à vontade com o strtok.

Os patterns do teu scanf estão completamente errados...

%[^\n]s

isto faz match com tudo excepto o '\n'. Ou seja consome-te todo o input não deixando nada para o 3.º parâmetro. A única razão pela qual o teu exemplo "a bbb ccc" dá o 3.º parâmetro como ccc é por estares a escrever o segundo parâmetro fora da variável...

A título de exemplo, aumenta as tuas strings de 4 caracteres para 400, e vê o resultado...

Já agora, uma ajuda: Retirado do "man scanf"

Return Value

These functions return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.

The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs. EOF is also returned if a read error occurs, in which case the error indicator for the stream (see ferror(3)) is set, and errno is set indicate the error.

Ou seja o scanf retorna o número de variáveis que consegui efectivamente ler, logo

a=scanf("%[^\n]c %[^\n]s %[^\n]\n", &b.v1, b.v2, b.v3);

printf("resultado scanf:%d\n",a);

vai-te dizer quantos argumentos conseguiu ler.

Editado por Flinger
  • Voto 1

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
JoaoSkate

obrigado pela ajuda,

eu estava a tentar evitar usar o fgets, e usar apontadores, porque eu estou ainda a aprender e ainda nao cheguei a essas partes mais complicadas, eu já fui ver como funciona o fgets mas nao percebi mt bem com funciona. Mas ainda vou tenntar ver de novo.

no entanto arranjei agora uma forma simples para ler uma frase completa:

#include 
#define DIM 10
#include 

int main()
{
int c, i=0;
char vetor[DIM];
while(i vetor[i++] = c;

vetor[i] = '\0';


printf("%s\n",vetor); //testando

return 0;
}

agorapor exemplo quando insiro : a bbb ccc

fica guardado no vetor esta string "a bbb ccc" e eu quero partir essa string em 3 e guardar em novas strings(vetores) o a, o bbb, ccc, para guardar o 'a' eu já tentei fazer por exmplo

nova_varialvel=vetor[0] 

mas dá me segmetation fault, e o que estava a pensar fazer para o bbb e o cc era usar o strcpy, para copiar a string completa a bbb ccc para uma nova string bbb

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

A tua variável vector[DIM], indirectamente é um ponteiro.

O fgets lê uma string do buffer de entrada para uma variável já declarada.

Por exemplo:

fgets (vector, DIM, stdin);

lê uma string do buffer de entrada 'stdin' e armazena-a em 'vector', isto sem entrar em muitos detalhes.

No entanto, para depois tratares da string após ter sido armazenada em 'vector', precisas de saber, pelo menos dois detalhes:

1-o fgets também guarda em 'vector', o <enter> que usamos quando inserimos a string.

2-o fgets adiciona um carácter especial à string que a sinaliza como tal. Ou seja, uma string, para ser uma string tem que ter obrigatoriamente este caractér especial no final. É o NULL character ou terminador de string, acho que é assim o nome.

Exemplo:

A string "o rato roeu a rolha"

lida com o fgets, fica com este aspecto depois de guardada em 'vector':

o rato roeu a rolha\n\0

O \n é o <enter>e o \0 é o tal NULL char que sinaliza a string, como sendo uma string.

Ps: se o teu último código funciona, eu não consigo perceber como. Falta pelo menos um parêntesis no argumento do while, a variável 'c' não inicializada poder ser um problema é a variável 'i' se for a que controla o loop while e sem ser alterada, vai impedir o Code do while de ser executado e ainda o factor de não ver nenhuma função de leitura do buffer de entrada.

Editado por PsySc0rpi0n

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Flinger

Recomendamos o fgets, porque a versão simples, o gets é altamente desaconselhada por questões de segurança.

Mas para efeitos práticos, o fgets com o valor do 3.º parágrafo stdin, é efectivamente igual ao gets mas mais seguro.

Quanto ao primeiro parâmetro, o char *, estás usar o mesmo que usas no scanf e no printf, por isso nada de novo.

char *fgets(char *s, int size, FILE *stream)
int scanf(const char *format, ...);

A única coisa que precisas saber é:

int main()
{
   char input[1024];
   fgets(input,1024,stdin);
   printf("%s",input);
}

O fgets lê-te uma linha inteira (até ao enter,incluído), com um tamanho máximo de 1024 - 1 (este último char fica para o \0).

Editado por Flinger
  • Voto 1

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Eu também só vou dizer isto mais uma vez:

Usa o fgets... Se ainda nãod este apontadores nas aulas, então também não podes usar vectores de strings! Nem vectores, de uma forma geral...

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.