Ir ao conteúdo
  • Cadastre-se

C Imprime as letras vogais de uma string se o tamanho dela for impar <string.h>


Posts recomendados

Tem algum código mais eficiente do que esse? eu quebrei a cabeça com isso:

Questão --> 

O processamento de dados textuais, atualmente, é bastante avançado, e já existem
bibliotecas capazes de auxiliar neste tipo de situação. Elabore um programa que leia
uma palavra e, se ela tiver número ímpar de caracteres, imprima todas as suas vogais.

#include <stdio.h>
#include <string.h>
#define max 10
int main()
{
	char palavra[max];
	int i;
	char letra;
	printf("Digite uma palavra: ");
	scanf("%s", palavra);
	strlwr(palavra);
	if (strlen(palavra) % 2 == 1)
	{
		for (i = 0; i < max; i++)
		{
			letra = palavra[i];
			switch (letra)
			{
				case 'a' : printf("%c", letra);
					break;
				case 'e' : printf("%c", letra);
					break;
				case 'i' : printf("%c", letra);
					break;
				case 'o' : printf("%c", letra);
					break;
				case 'u' : printf("%c", letra);
					break;			
			}
		}
	}
}

 

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

@AnonymousLPH Não precisa usar um case para cada vogal...

Acho que 9 caracteres não são suficiente. Não esqueça que é interessante limitar a quantidade de caracteres que podem ser inseridos colocando a quantidade após o % na função scanf().

Acho bacana não imprimir vogal por vogal, mas passar as vogais para outra string e depois imprimir.

Faltou também um else para caso a quantidade de caracteres for um número par.

#include <stdio.h>
#include <string.h>
#define max 31
int main()
{
	char palavra[max];
	char novapalavra[max];
	int i, cont = 0;
	char letra;
	printf("Digite uma palavra: ");
	scanf("%30s", palavra);

	if (strlen(palavra) % 2 == 1)
	{
		for (i = 0; i < max; i++)
		{
			letra = palavra[i];
			if(letra=='a'||letra=='e'||letra=='i'||letra=='o'||letra=='u'){
                novapalavra[cont++] = letra;
            }
		}
		//Se quantidade de caracteres for ímpar, imprime
		printf("%s", novapalavra);
	} else {
	    //Se for par, retorna 0
	    return 0;
	}
	return 0;
}

 

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

Um switch menor e mais legível pode ser assim:

//3 cases com mesmo código
switch (letra) {
	case 'a':
		printf("%c", letra);
		break;
	case 'c':
		printf("%c", letra);
		break;
	case 'e':
		printf("%c", letra);
		break;
}

//como são o mesmo código no switch, basta fazer assim:
switch (letra) {
	case 'a':
	case 'c':
	case 'e':
		printf("%c", letra);
}

//esse código acima é o mesmo que esse abaixo:
if (letra == 'a' || letra == 'c' || letra == 'e')
  printf("%c", letra);

 

Link para o comentário
Compartilhar em outros sites

Não simplifica; Crie funções novas e utilize as que já tem em <string.h>

 

P. ex:

/*------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------*/

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

#define MAX 10

#define CSIZ(x) #x
#define SCN_S(x) "%" CSIZ(x) "s"
int scanf_de (char *palavra){
	size_t n = scanf (SCN_S(MAX), palavra);
	return n;
}//---- FIM_SCANF_DE
int printf_de (const char *palavra, const char *sequencia){
	char *lra = strpbrk (palavra, sequencia);
	size_t cdor = 0;

		while (lra != NULL){
			printf ("%c", *lra);
			lra = strpbrk (lra + 1, sequencia);
			++ cdor;
		}
	return cdor;
}//---- FIM_PRINTF_DE
int main (void){
	char palavra [MAX + 1] = {""};

	printf ("Digite uma palavra com %d letras: ", MAX);
	scanf_de (palavra);
	
	size_t tamanho = strlen (palavra);
	if (tamanho % 2 == 1){
		printf_de (palavra, "aeiouAEIOU");
	} 
	return 0;
}//---- FIM_MAIN

 

Link para o comentário
Compartilhar em outros sites

Em 01/07/2020 às 23:52, AnonymousLPH disse:
Em 01/07/2020 às 23:52, AnonymousLPH disse:

Tem algum código mais eficiente do que esse? eu quebrei a cabeça com isso

 

Elabore um programa que leia
uma palavra e, se ela tiver número ímpar de caracteres, imprima todas as suas vogais

 

Desprezou de propósito as vogais maiúsculas?


Em termos de eficiência não considere escrever ou chamar novas funções porque estaria indo na contra-mão. Se procura eficiência dificilmente vai encontrar por esse caminho.

 

Nesse caso aqui o mais eficiente é não ter processamento algum e usar uma matriz de referência onde estão marcadas as letras que você que ler.

 

E considere que para saber que a palavra tem um número ímpar de caracteres você tem que ler a palavra toda, porque em C uma "palavra" é uma sequência TERMINADA por zero, o NULL, o '\0'. Assim pra saber que terminou você já leu tudo. E pra saber o tamanho você conta tudo de novo. E depois para achar as vogais você olha tudo de novo. TRÊS vezes. Nada eficiente.

Espero que tenha ficado claro.

 

No critério eficiência, então palavra é
 

char palavra[max]
 

Em um char cabem 256 bytes.  Então use um vetor de 256 bytes onde cada posição tem 0 ou 1 por exemplo. '1' para as vogais. Pronto. 256 bytes não é nada em termos de espaço. E esse tipo de operação é, digamos, instantânea em C. E não leia a palavra em palavra[max]. Leia apenas uma letra por vez e só coloque em palavra as vogais. Ao encontrar o zero que termina a entrada você vê se a palavra é par ou ímpar. Se for ímpar você imprime a string que só vai ter as vogais.


O custo de chamar uma função em C ou qualquer linguagem é enorme se comparado a testar um byte contra uma constante.

Em termos de eficiência esse é o caminho. Não chame qualquer função, não leia a palavra para depois ver o tamanho para depois ver se é ímpar pra depois procurar as vogais.

 

Link para o comentário
Compartilhar em outros sites

Em 01/07/2020 às 23:52, AnonymousLPH disse:

Tem algum código mais eficiente do que esse?

 

Em busca de eficiência

 

Aqui está varrendo a string várias vezes em seguida...
 

image.png.86af2fe688cfac23cc8faf4fbe499344.png

 

  • scanf() para colocar as letras no vetor
     
  • strlwr() para converter TUDO para minúscula. É discutível porque vai converter espaços, vogais, consoantes, símbolos, tudo que tem lá. Vai varrer a string toda de novo e seu programa só trata as vogais. Não é nada eficiente trocar 'F' por 'f' e '/' por '/' mesmo, a toa. E depois não fazer nada com isso.
     
  • strlen(palavra) vai varrer a string toda de novo a partir do endereço palavra, até encontrar um zero, e aí vai retornar a diferença entre o endereço do zero e o endereço de início. Em resumo: vai ler tudo de novo pela terceira vez.
     
  • o for() vai ler tudo de novo outra vez, agora em busca das vogais. A quarta vez.
     
Em 02/07/2020 às 00:06, Lucca Rodrigues disse:

Não precisa usar um case para cada vogal...

 

Em termos de código gerado não muda praticamente nada. Em termos de eficiciência é a mesma coisa

Em 02/07/2020 às 00:06, Lucca Rodrigues disse:

Não esqueça que é interessante limitar a quantidade de caracteres que podem ser inseridos colocando a quantidade após o % na função scanf().

Acho bacana não imprimir vogal por vogal, mas passar as vogais para outra string e depois imprimir.

Faltou também um else para caso a quantidade de caracteres for um número par

 

Se busca eficiência scanf() não seria o caso aqui. Limitar a quantidade seria algo positivo em termos de segurança. O else está fora do propósito do enunciado: "imprimir as vogais da string se o comprimento for ímpar" é o objetivo

 

Em 03/07/2020 às 09:31, Midori disse:

scanf("%s", p);
if(strlen(p) % 2)
{
while(*p)
{


Está bem legível e bem escrito,  mas em termos de eficiência continua varrendo a string 3x em seguida.
 

19 horas atrás, Mauro Britivaldo disse:

int scanf_de() ...


int scanf_de (char *palavra){
	size_t n = scanf (SCN_S(MAX), palavra);
	return n;
}//---- FIM_SCANF_DE

int printf_de (const char *palavra, const char *sequencia){
	char *lra = strpbrk (palavra, sequencia);
	size_t cdor = 0;

		while (lra != NULL){
			printf ("%c", *lra);
			lra = strpbrk (lra + 1, sequencia);
			++ cdor;
		}
	return cdor;
}//---- FIM_PRINTF_DE
int main (void){
	char palavra [MAX + 1] = {""};

	printf ("Digite uma palavra com %d letras: ", MAX);
	scanf_de (palavra);
	
	size_t tamanho = strlen (palavra);
	if (tamanho % 2 == 1){

Em termos de eficiência deve ser mais de 100 vezes mais lento no tratamento da string que o original, que já era lento.

  • scanf_de() é uma função e chama scanf() de novo. Função dentro de função.
  • printf_de() usa dois ponteiros e chama strpbrk() no início e depois tem outro loop que chama strpbrk() de novo DENTRO do loop, multiplicando o overhead. Com dois ponteiros como parâmetro. E um deles é uma constante literal...  Isso quer dizer pegar os dois ponteiros, empilhar, desempilhar, achar os endereços, chamar as funções e fazer eventualmente isso de novo dentro do loop para cada símbolo, seja ou não uma vogal. São centenas de chamadas de função. Nada eficiente.

O mais eficiente é ler uma única vez. Não chamar qualquer função. E usar uma tabela de referência.

 

 

 

 

adicionado 11 minutos depois

Em termos de eficiência procurem sempre algo assim:

#include <stdio.h>
#include "ref.h"
int main()
{	char    palavra[30], * p = palavra;
	char    c = 0;
	int     n = 0; // letras na palavra lida
	while ((c = fgetc(stdin)) != '\n')
	{
		n++; // leu mais uma letra
		if (idx[c]) *p++ = c; // guarda a vogal
	};	// while()
	*p = 0; // termina a string
	if ((p > palavra) && (n%2 == 1)) printf("%s\n", palavra);
};  // 1464369

Sem redundância, uma única leitura e tratamento de cada letra.

 

em ref.h tem só a matriz de referência, que tem a lógica do filtro embutida

const char idx[256] =
{
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 000-015
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 016-031
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 032-047
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 048-063
  0,  65,   0,   0,   0,  69,   0,   0,   0,  73,   0,   0,   0,   0,   0,  79,  // 064-079
  0,   0,   0,   0,   0,  85,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 080-095
  0,  97,   0,   0,   0, 101,   0,   0,   0, 105,   0,   0,   0,   0,   0, 111,  // 096-111
  0,   0,   0,   0,   0, 117,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 112-127
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 128-143
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 144-159
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 160-175
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 176-191
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 192-207
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 208-223
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 224-239
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0   // 240-255
}; // ARFNeto '20

isso é tão comum que em geral gente tem um programa que escreve a declaração em C e já testa o filtro...

 

 

adicionado 19 minutos depois

O programa em um arquivo só:
 

Spoiler

#include <stdio.h>

const char idx[256] =
{
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 000-015
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 016-031
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 032-047
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 048-063
  0,  65,   0,   0,   0,  69,   0,   0,   0,  73,   0,   0,   0,   0,   0,  79,  // 064-079
  0,   0,   0,   0,   0,  85,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 080-095
  0,  97,   0,   0,   0, 101,   0,   0,   0, 105,   0,   0,   0,   0,   0, 111,  // 096-111
  0,   0,   0,   0,   0, 117,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 112-127
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 128-143
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 144-159
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 160-175
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 176-191
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 192-207
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 208-223
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 224-239
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0   // 240-255
}; // ARFNeto '20

int main()
{    char    palavra[30], * p = palavra;
    char    c = 0;
    int     n = 0; // letras na palavra lida
    while ((c = fgetc(stdin)) != '\n')
    {
        n++; // leu mais uma letra
        if (idx[c]) *p++ = c; // guarda a vogal
    };    // while()
    *p = 0; // termina a string
    if ((p > palavra) && (n%2 == 1)) printf("%s\n", palavra);
};  // 1464369

 

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

15 minutos atrás, Mauro Britivaldo disse:

Uffa! Ainda bem! Porque eficiência não é o meu forte, e não foi essa a intenção


😃🤔 escreveu em  resposta a uma questão que começa assim:

 

Em 01/07/2020 às 23:52, AnonymousLPH disse:

Tem algum código mais eficiente do que esse? eu quebrei a cabeça com isso


Entendeu o exemplo que mostrei e as coisas que expliquei sobre as chamadas de função?
 

 

 

Link para o comentário
Compartilhar em outros sites

2 horas atrás, arfneto disse:

#include <stdio.h> const char idx[256] = {   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 000-015   0,   0,   0,

Boa alternativa.

 

Outra forma de carregar a matriz poderia ser assim,

 

    char idx[256]={0};
    idx[65]='A'; idx[97]='a';
    idx[69]='E'; idx[101]='e';
    idx[73]='I'; idx[105]='i';
    idx[79]='O'; idx[111]='o';
    idx[85]='U'; idx[117]='u';

 

Pela quantidade de testes (OU) este código ainda não seria tão eficiente quando o outro com a matriz de referência, não é?

 

#include <stdio.h>

int main(){
    char c, palavra[20]={0}, *p = palavra;
    int i = 0;

    while((c = fgetc(stdin)) != '\n'){
        if(c=='a'||c=='e'||c=='i'||c=='o'||c=='u'||
        c=='A'||c=='E'||c=='I'||c=='O'||c=='U'){
            *p++ = c;
        }
        i++;
    }

    if(i % 2) printf("%s", palavra);
    
    return 0;
}

 

Link para o comentário
Compartilhar em outros sites

🤔

 

 

 

adicionado 16 minutos depois
12 minutos atrás, Midori disse:

Pela quantidade de testes (OU) este código ainda não seria tão eficiente quando o outro com a matriz de referência, não é

 

Não. A inicialização do bloco estático vai estar no código gerado, tanto faz. Mas as 10 atribuições são variáveis. Toda vez que rodar o programa vai executar isso absolutamente a toa. Se vai julgar eficiência não pode atribuir toda vez a mesma coisa para as mesmas variáveis. Porque não fazer o simples e colocar lá no bloco?

 

O bloco foi escrito por um programa curtinho, porque é uma coisa comum que aparece toda hora que se trata entrada. Os valores já estão lá em ordem.

 

A atribuição que fez aqui em

char idx[256]={0};

    idx[65]='A'; idx[97]='a';
    idx[69]='E'; idx[101]='e';
    idx[73]='I'; idx[105]='i';
    idx[79]='O'; idx[111]='o';
    idx[85]='U'; idx[117]='u';

você faz uma vez só digitando sobre o bloco de 16x16, uma vez só.


const char idx[256] =
{

  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 000-015
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 016-031
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 032-047
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 048-063
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 064-079
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 080-095
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 096-111
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 112-127
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 128-143
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 144-159
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 160-175
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 176-191
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 192-207
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 208-223
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 224-239
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0  // 240-255

}; // ARFNeto '20

Em um caso eram as vogais, numa outra os dígitos, numa outra um conjunto de até 256 pacotes a despachar numa van, depende do sistema... E na matriz você pode colocar já o código de saída, então ela embute parte da lógica sem NENHUM processamento. Apenas x = f(x), a coisa mais rápida que os processadores fazem.

 

Isso que escreveu são instruções a executar, ciclos de CPU

 while((c = fgetc(stdin)) != '\n'){
        if(c=='a'||c=='e'||c=='i'||c=='o'||c=='u'||
        c=='A'||c=='E'||c=='I'||c=='O'||c=='U'){
            *p++ = c;
        }
        i++;
    }

Por outro lado

		if (idx[c]) *p++ = c; // guarda a vogal

Isso é uma tabela de referência --- look-up --- e não tem qualquer processamento. A lógica foi embutida em tempo de compilação. 

 

Exemplo

 

Se quisesse trocar as vogais por um '#' bastaria colocar em idx[] nas posições corretas  o '#' e no if escrever 

		if (idx[c]) *p++ = idx[c]; // guarda o valor

Se quisesse converter as vogais para minúscula ou maiúscula bastaria alterar a tabela de acordo. Se lesse a tabela de um arquivo ou recebesse de outro programa não precisaria fazer nada: a lógica viria embutida.

 

 

Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

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...