Ir ao conteúdo
  • Cadastre-se

C Recursividade. Comparar Caracteres De Duas Strings.


jcgs98
Ir à solução Resolvido por jcgs98,

Posts recomendados

#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

int comparaString (char str1[100],char str2[100]);

int main(void)
	{
		int cont=0;
		
		char str1[100],str2[100];
		
		system("cls");
		fflush(stdin);
		printf("\nString1...:\n");
		gets(str1);
		system("cls");
		fflush(stdin);
		printf("\nString2...:\n");
		gets(str2);
		
		cont=comparaString (str1,str2);
		
		printf("\nExistem %i caracteres comuns entre as duas strings\n",cont);
		
		return 0;
	}
	
int comparaString (char str1[100],char str2[100])
{
		int i,j,cont=0;
		
		for(i=0;str1[i]!=NULL;i++)
		{
			for(j=0;str2[j]!=NULL;j++)
			{
				if(str1[i]==str2[j])
				{
					cont++;
				}
			}
		}
		
		return cont;
}

Como fazer de forma totalmente recursiva?

Link para o comentário
Compartilhar em outros sites

int comparaString (char str1[100],char str2[100])
{
		int i,j,cont=0;
		
		for(i=0;str1[i]!=NULL;i++)
		{
			for(j=0;str2[j]!=NULL;j++)
			{
				if(str1[i]==str2[j])
				{
					cont++;
				}
			}
		}	
		return cont;
}

 

Ainda sobre a função como escreveu:

  • imagino que pretendesse retornar false quando as strings fossem diferentes, zero no popular.  E 1 quando forem iguais, mas está contando e retornando apenas o número de letras iguais. Ou pretendia apenas retornar o número de vezes que alguma letra de str1 aparece em str2 ou algo assim? Acho que te qualquer maneira não está certo porque está comparando todas as letras de str2 com cada letra de str1 e isso pode não ter um significado objetivo, já que as strings podem ter letras repetidas... Escreva explicando o que pretende se não é comparar as strings apenas.
     
    De qualquer forma o que vou te mostrar se aplica do mesmo modo.

     
  • um "problema": não declare variáveis de controle fora do loop, em especial ums com nomes comuns tipo i e j como aqui. Isso sempre cai na sua cabeça. A comunidade lutou por anos até o comitê ISO que controla C mudar a linguagem para aceitar essas declarações no próprio for. Só que foi no final dos anos 80. É norma em toda empresa que tenha um código de aderência para programação, em toda escola séria: nada de globais, total foco na redução de escopo de variáveis. Nada de variáveis de controle soltas pelo programa. Tanto é assim que desde '17 por exemplo em C++ se pode declarar variáveis dentro de if() e switch() também, e variáveis podem ser declaradas dentro de qualquer bloco {}.
     

  • evite char[]. Não é relevante e só limita as coisas. Deixe char* ou melhor const char* assim fica claro que não vai mudar a entrada e que a função pode ser chamada com literais ou ponteiros 
     

  • outra "norma" comum a todos os guias de boas práticas: não declare mais que uma variável por linha. Inicialize todas as variáveis.

Claro que software é um trabalho criativo e cada um tem suas idéias. Mas hoje em dia mal se consegue escolher a linguagem. E quando trabalha para uma empresa grande ou mesmo pequena tem que se ater às regras locais. Isso pode e em geral significa coisas como

  • tamanho máximo de uma função em número de linhas
  • regras precisas sobre onde colocar colchetes, chaves, parênteses e vírgulas
  • regras para documentação e comentários
  • regras para sufixos ou prefixos de variáveis membro, nomes de funções e classes
  • limites para o número de colunas usadas, em geral 60
  • regras para alinhamento de comandos e declarações

E mais coisas do tipo. Um p0rr3. Mas a ideia é que qualquer um possa continuar o seu trabalho lá, e você possa continuar o trabalho de qualquer um. Em muitas escolas é assim também: alguém manda.

 

De volta o ao programa:
 

int comparaString2 (char* str1, char* str2 )
{
    while( *str1 != 0 )
    {
        if ( *str2 == 0 ) return 0;
        if( *str1 != *str2 ) return 0;
        str1+=1; str2+=1;
    };
    return ( *str2 == 0);
};  


Algo assim já funcionaria. Veja que não precisa de nenhuma variável. E assim é mais eficiente. Na dúvida meça.

 

E a recursão afinal?


Esse é um exemplo comum de recursão para iniciantes, mas não é esperto: iterar em um vetor, como o caso da função que escreveu e dessa aí acima que eu mostrei, É muito mais eficiente que usar recursão. Como dez ou vinte vezes mais rápido. Centenas de vezes se as strings são grandes. E não usa memória extra nem nada.


Estamos entrando em uma época em que tudo vai pra tal nuvem e a CPU é cobrada por segundo no Azure, GCloud, Amazon... :) 

 

De volta ao problema:


Pensando do modo recursivo você só pensa em uma letra: se elas são iguais você anda uma posição nas strings e continua. Assim que achar uma diferença para o ciclo e retorna.


Pode ser algo simples assim em 😄

 

int comparaString3 ( char* str1, char* str2 )
{
    if ( *str1 != 0 )
    {
        if ( *str2 == 0 )       return 0;
        if ( *str1 == *str2 )   return comparaString3( ++str1, ++str2 );
        return 0;
    }
    else
        return ( *str2 == 0 );
};

 

Pode usar essa para comparar os resultados entre as funções, por exemplo entre as 3 versões aqui:
 

void testaF(
    unsigned n, const char* teste[][2],
    int(*f)(char*,char*), const char* msg)
{
   	if( msg != NULL )
        printf("\n\n%s\n\n\t==> %d testes:\n\n",msg,n);
    else
   	    printf ( "\n\n==> %d testes:\n\n", n );

 	for (int i=0;i<n;i++)
    {
         printf("\
%02d/%02d  \"%s\" vs \"%s\" retornou %d\n",
        1+i,n, teste[i][0], teste[i][1], 
        f( (char*) teste[i][0], (char*) teste[i][1] ) );
      }; // for()

 

Para usar é trivial, usando uma tabela teste de strings para acelerar os testes comuns:

 

    int n = sizeof(teste)/(2 * sizeof(char*));
    testaF( n, teste,
        comparaString2, 
        "Usando funcao iterativa");

    testaF( n, teste,
        comparaString, 
        "Usando funcao original");

    testaF( n, teste,
        comparaString3, 
        "Usando funcao recursiva");

 

Para essa tabela
 

  	const char* teste[][2] =
      {
          { "azul", "azul" },
          { "zul", "azul" },
          { "azul", "zul" },
          { "", "azul" },
          { "", "" },
          { "uma string", "uma string" },
          { "uma string", "uma strinG" },
          { "coisa", "" }
       };

 

Mostraria
 


Usando funcao iterativa

        ==> 8 testes:

01/08  "azul" vs "azul" retornou 1
02/08  "zul" vs "azul" retornou 0
03/08  "azul" vs "zul" retornou 0
04/08  "" vs "azul" retornou 0
05/08  "" vs "" retornou 1
06/08  "uma string" vs "uma string" retornou 1
07/08  "uma string" vs "uma strinG" retornou 0
08/08  "coisa" vs "" retornou 0


Usando funcao original

        ==> 8 testes:

01/08  "azul" vs "azul" retornou 4
02/08  "zul" vs "azul" retornou 3
03/08  "azul" vs "zul" retornou 4
04/08  "" vs "azul" retornou 0
05/08  "" vs "" retornou 0
06/08  "uma string" vs "uma string" retornou 10
07/08  "uma string" vs "uma strinG" retornou 10
08/08  "coisa" vs "" retornou 5


Usando funcao recursiva

        ==> 8 testes:

01/08  "azul" vs "azul" retornou 1
02/08  "zul" vs "azul" retornou 0
03/08  "azul" vs "zul" retornou 0
04/08  "" vs "azul" retornou 0
05/08  "" vs "" retornou 1
06/08  "uma string" vs "uma string" retornou 1
07/08  "uma string" vs "uma strinG" retornou 0
08/08  "coisa" vs "" retornou 0

 

A vantagem desa técnica --- comum --- é que você pode editar a tabela e ir acrescentando ou excluindo strings de teste e automaticamente testar o programa com TODAS as string e TODAS as funções, sem mudar nada.

 

Note que a função original ainda está sem a correção que eu sugeri. comparaString() é a função que escreveu.

comparaString2() é a função que eu mostrei. comparaString3() é a versão recursiva.

Se não era isso que pretendia testar escreva de novo para eu entender o que quer comparar e o resultado que espera. E me desculpe ;) 

 

Eis o programa de teste:

Spoiler

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

int comparaString (char[100],char [100]);
int comparaString2 (char*, char* );
int comparaString3 (char*, char* );

void testaF(unsigned, const char*[][2],
    int(*)(char*,char*), const char* );

int main()
{
  	const char* teste[][2] =
      {
          { "azul", "azul" },
          { "zul", "azul" },
          { "azul", "zul" },
          { "", "azul" },
          { "", "" },
          { "uma string", "uma string" },
          { "uma string", "uma strinG" },
          { "coisa", "" }
       };

    int n = sizeof(teste)/(2 * sizeof(char*));

    testaF( n, teste,
        comparaString2, 
        "Usando funcao iterativa");

    testaF( n, teste,
        comparaString, 
        "Usando funcao original");

     testaF( n, teste,
        comparaString3, 
        "Usando funcao recursiva");

  	return 0;
};

int comparaString (char str1[100],char str2[100])
{
		int i,j,cont=0;
		
		for(i=0;str1[i]!=0;i++)
		{
			for(j=0;str2[j]!=0;j++)
			{
				if(str1[i]==str2[j])
				{
					cont++;
				}
			}
		}
	
		return cont;
}

int comparaString2 (char* str1, char* str2 )
{
    while( *str1 != 0 )
    {
        if ( *str2 == 0 ) return 0;
        if( *str1 != *str2 ) return 0;
        str1+=1; str2+=1;
    };
    return ( *str2 == 0);
};  

int comparaString3 ( char* str1, char* str2 )
{
    if ( *str1 != 0 )
    {
        if ( *str2 == 0 )       return 0;
        if ( *str1 == *str2 )   return comparaString3( ++str1, ++str2 );
        return 0;
    }
    else
        return ( *str2 == 0 );
};  

void testaF(
    unsigned n, const char* teste[][2],
    int(*f)(char*,char*), const char* msg)
{
   	if( msg != NULL )
        printf("\n\n%s\n\n\t==> %d testes:\n\n",msg,n);
    else
   	    printf ( "\n\n==> %d testes:\n\n", n );

 	for (int i=0;i<n;i++)
    {
         printf("\
%02d/%02d  \"%s\" vs \"%s\" retornou %d\n",
        1+i,n, teste[i][0], teste[i][1], 
        f( (char*) teste[i][0], (char*) teste[i][1] ) );
      }; // for()

};

 

 

 

 

Link para o comentário
Compartilhar em outros sites

@arfneto Vou tentar entender os código... não consigo pensar recursivamente.

@arfneto "imagino que pretendesse retornar false quando as strings fossem diferentes, zero no popular.  E 1 quando forem iguais, mas está contando e retornando apenas o número de letras iguais. Ou pretendia apenas retornar o número de vezes que alguma letra de str1 aparece em str2 ou algo assim? Acho que te qualquer maneira não está certo porque está comparando todas as letras de str2 com cada letra de str1 e isso pode não ter um significado objetivo, já que as strings podem ter letras repetidas... Escreva explicando o que pretende se não é comparar as strings apenas."

Não, retornar a quantidade de letras em comum.

Link para o comentário
Compartilhar em outros sites

1 hora atrás, Comunista.RJ disse:

Não, retornar a quantidade de letras em comum

 

entendi. Então está bem errado mesmo o modo como escreveu. Ou nem tanto 🤔 Vou alterar o exemplo quando der tempo. ;) e pensar em como isso pode ser feito recursivamente. É mais complicado que uma strcmp() recursiva seria :) 

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

10 minutos atrás, Comunista.RJ disse:

Não, a forma iterativa está certa. Retorna a quantidade de caracteres em comum

para isso estar "certo" precisa de uma definição mais precisa e talvez mais liberal de como tratar as letras repetidas na primeira E na segunda string. 

 

Aí pode estar certo, ou bem errado...

 

Se a primeira string tem 30 'a' e a segunda tem 45 'a' vai retornar o que? Definindo seguramente o que chama de "letras duplicadas" aí se pode ver a resposta com segurança. É como a diferença entre arranjos e permutações. Defina o que pretende contar.

 

 

 

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

@arfneto

// 50% recursiva... tentando ainda!

int comparaString (char str1[100],char str2[100])
{
	int i,j,cont=0;
	
	for(i=0;str1[i]!=NULL;i++)
	{
		cont=cont+comparaString2(str1[i],str2);
	}
		
	return cont;
}

int comparaString2(char str1,char str2[])
{
 	if (!str2[0])
	{
	 	return 0;
 	}
	
	if (str2[0]==str1)
	{
		return (1+comparaString2(str1,++str2));
	}
	
	else
	{
		return comparaString2(str1,++str2);	
	}
}

 

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

Muito bem. Mas qual a definição de repetição? Como trata "aaaaaaaa" e "aaaaaaaaaaaaaaaa"? Que faz para 8 e 6 'a' por exemplo? O lance da recursão é como está no exemplo que mostrei. Só que a cada nível de recursão precisa saber que já pode ter contabilizado antes aquela letra na string1 e manter essa memória em recursão é chato. ode precisar de uma estrutura static. Entendeu o que falei sobre a definição mais ou menos liberal de "contar as letras repetidas", imagino.

 

 

não use char[100]. É limitante a toa. Se possível use "const char*".

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

@arfneto não importa. cada "a" é considerado um "a" diferente.

Esse foi o desafio:
Develop a recursive function that determines the number of common characters between two strings s1 and s2. Grades: i. The solution must be in the C programming language; ii. If the same character appears n times in a given string, it will not be considered an error if your solution counts this character n times; iii. If your solution is broken down into more than one function (so that the main one - which solves the proposed problem - calls other helpers), all functions must be recursive;

@arfneto "não use char[100]. É limitante a toa. Se possível use "const char*"."

Sim, depois eu deixo o código elegante.

18 minutos atrás, Comunista.RJ disse:

@arfneto não importa. cada "a" é considerado um "a" diferente.

Esse foi o desafio:
Develop a recursive function that determines the number of common characters between two strings s1 and s2. Grades: i. The solution must be in the C programming language; ii. If the same character appears n times in a given string, it will not be considered an error if your solution counts this character n times; iii. If your solution is broken down into more than one function (so that the main one - which solves the proposed problem - calls other helpers), all functions must be recursive;

@arfneto "não use char[100]. É limitante a toa. Se possível use "const char*"."

Sim, depois eu deixo o código elegante.

@arfneto "um "problema": não declare variáveis de controle fora do loop, em especial ums com nomes comuns tipo i e j como aqui. Isso sempre cai na sua cabeça. A comunidade lutou por anos até o comitê ISO que controla C mudar a linguagem para aceitar essas declarações no próprio for. Só que foi no final dos anos 80. É norma em toda empresa que tenha um código de aderência para programação, em toda escola séria: nada de globais, total foco na redução de escopo de variáveis. Nada de variáveis de controle soltas pelo programa. Tanto é assim que desde '17 por exemplo em C++ se pode declarar variáveis dentro de if() e switch() também, e variáveis podem ser declaradas dentro de qualquer bloco {}."

 

arquivos ".c" não aceitam declarar a variável dentro do for

7 horas atrás, arfneto disse:

int comparaString (char str1[100],char str2[100])
{
		int i,j,cont=0;
		
		for(i=0;str1[i]!=NULL;i++)
		{
			for(j=0;str2[j]!=NULL;j++)
			{
				if(str1[i]==str2[j])
				{
					cont++;
				}
			}
		}	
		return cont;
}

 

Ainda sobre a função como escreveu:

  • imagino que pretendesse retornar false quando as strings fossem diferentes, zero no popular.  E 1 quando forem iguais, mas está contando e retornando apenas o número de letras iguais. Ou pretendia apenas retornar o número de vezes que alguma letra de str1 aparece em str2 ou algo assim? Acho que te qualquer maneira não está certo porque está comparando todas as letras de str2 com cada letra de str1 e isso pode não ter um significado objetivo, já que as strings podem ter letras repetidas... Escreva explicando o que pretende se não é comparar as strings apenas.
     
    De qualquer forma o que vou te mostrar se aplica do mesmo modo.

     
  • um "problema": não declare variáveis de controle fora do loop, em especial ums com nomes comuns tipo i e j como aqui. Isso sempre cai na sua cabeça. A comunidade lutou por anos até o comitê ISO que controla C mudar a linguagem para aceitar essas declarações no próprio for. Só que foi no final dos anos 80. É norma em toda empresa que tenha um código de aderência para programação, em toda escola séria: nada de globais, total foco na redução de escopo de variáveis. Nada de variáveis de controle soltas pelo programa. Tanto é assim que desde '17 por exemplo em C++ se pode declarar variáveis dentro de if() e switch() também, e variáveis podem ser declaradas dentro de qualquer bloco {}.
     

  • evite char[]. Não é relevante e só limita as coisas. Deixe char* ou melhor const char* assim fica claro que não vai mudar a entrada e que a função pode ser chamada com literais ou ponteiros 
     

  • outra "norma" comum a todos os guias de boas práticas: não declare mais que uma variável por linha. Inicialize todas as variáveis.

Claro que software é um trabalho criativo e cada um tem suas idéias. Mas hoje em dia mal se consegue escolher a linguagem. E quando trabalha para uma empresa grande ou mesmo pequena tem que se ater às regras locais. Isso pode e em geral significa coisas como

  • tamanho máximo de uma função em número de linhas
  • regras precisas sobre onde colocar colchetes, chaves, parênteses e vírgulas
  • regras para documentação e comentários
  • regras para sufixos ou prefixos de variáveis membro, nomes de funções e classes
  • limites para o número de colunas usadas, em geral 60
  • regras para alinhamento de comandos e declarações

E mais coisas do tipo. Um p0rr3. Mas a ideia é que qualquer um possa continuar o seu trabalho lá, e você possa continuar o trabalho de qualquer um. Em muitas escolas é assim também: alguém manda.

 

De volta o ao programa:
 


int comparaString2 (char* str1, char* str2 )
{
    while( *str1 != 0 )
    {
        if ( *str2 == 0 ) return 0;
        if( *str1 != *str2 ) return 0;
        str1+=1; str2+=1;
    };
    return ( *str2 == 0);
};  


Algo assim já funcionaria. Veja que não precisa de nenhuma variável. E assim é mais eficiente. Na dúvida meça.

 

E a recursão afinal?


Esse é um exemplo comum de recursão para iniciantes, mas não é esperto: iterar em um vetor, como o caso da função que escreveu e dessa aí acima que eu mostrei, É muito mais eficiente que usar recursão. Como dez ou vinte vezes mais rápido. Centenas de vezes se as strings são grandes. E não usa memória extra nem nada.


Estamos entrando em uma época em que tudo vai pra tal nuvem e a CPU é cobrada por segundo no Azure, GCloud, Amazon... :) 

 

De volta ao problema:


Pensando do modo recursivo você só pensa em uma letra: se elas são iguais você anda uma posição nas strings e continua. Assim que achar uma diferença para o ciclo e retorna.


Pode ser algo simples assim em 😄

 


int comparaString3 ( char* str1, char* str2 )
{
    if ( *str1 != 0 )
    {
        if ( *str2 == 0 )       return 0;
        if ( *str1 == *str2 )   return comparaString3( ++str1, ++str2 );
        return 0;
    }
    else
        return ( *str2 == 0 );
};

 

Pode usar essa para comparar os resultados entre as funções, por exemplo entre as 3 versões aqui:
 


void testaF(
    unsigned n, const char* teste[][2],
    int(*f)(char*,char*), const char* msg)
{
   	if( msg != NULL )
        printf("\n\n%s\n\n\t==> %d testes:\n\n",msg,n);
    else
   	    printf ( "\n\n==> %d testes:\n\n", n );

 	for (int i=0;i<n;i++)
    {
         printf("\
%02d/%02d  \"%s\" vs \"%s\" retornou %d\n",
        1+i,n, teste[i][0], teste[i][1], 
        f( (char*) teste[i][0], (char*) teste[i][1] ) );
      }; // for()

 

Para usar é trivial, usando uma tabela teste de strings para acelerar os testes comuns:

 


    int n = sizeof(teste)/(2 * sizeof(char*));
    testaF( n, teste,
        comparaString2, 
        "Usando funcao iterativa");

    testaF( n, teste,
        comparaString, 
        "Usando funcao original");

    testaF( n, teste,
        comparaString3, 
        "Usando funcao recursiva");

 

Para essa tabela
 


  	const char* teste[][2] =
      {
          { "azul", "azul" },
          { "zul", "azul" },
          { "azul", "zul" },
          { "", "azul" },
          { "", "" },
          { "uma string", "uma string" },
          { "uma string", "uma strinG" },
          { "coisa", "" }
       };

 

Mostraria
 



Usando funcao iterativa

        ==> 8 testes:

01/08  "azul" vs "azul" retornou 1
02/08  "zul" vs "azul" retornou 0
03/08  "azul" vs "zul" retornou 0
04/08  "" vs "azul" retornou 0
05/08  "" vs "" retornou 1
06/08  "uma string" vs "uma string" retornou 1
07/08  "uma string" vs "uma strinG" retornou 0
08/08  "coisa" vs "" retornou 0


Usando funcao original

        ==> 8 testes:

01/08  "azul" vs "azul" retornou 4
02/08  "zul" vs "azul" retornou 3
03/08  "azul" vs "zul" retornou 4
04/08  "" vs "azul" retornou 0
05/08  "" vs "" retornou 0
06/08  "uma string" vs "uma string" retornou 10
07/08  "uma string" vs "uma strinG" retornou 10
08/08  "coisa" vs "" retornou 5


Usando funcao recursiva

        ==> 8 testes:

01/08  "azul" vs "azul" retornou 1
02/08  "zul" vs "azul" retornou 0
03/08  "azul" vs "zul" retornou 0
04/08  "" vs "azul" retornou 0
05/08  "" vs "" retornou 1
06/08  "uma string" vs "uma string" retornou 1
07/08  "uma string" vs "uma strinG" retornou 0
08/08  "coisa" vs "" retornou 0

 

A vantagem desa técnica --- comum --- é que você pode editar a tabela e ir acrescentando ou excluindo strings de teste e automaticamente testar o programa com TODAS as string e TODAS as funções, sem mudar nada.

 

Note que a função original ainda está sem a correção que eu sugeri. comparaString() é a função que escreveu.

comparaString2() é a função que eu mostrei. comparaString3() é a versão recursiva.

Se não era isso que pretendia testar escreva de novo para eu entender o que quer comparar e o resultado que espera. E me desculpe ;) 

 

Eis o programa de teste:

  Ocultar conteúdo


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

int comparaString (char[100],char [100]);
int comparaString2 (char*, char* );
int comparaString3 (char*, char* );

void testaF(unsigned, const char*[][2],
    int(*)(char*,char*), const char* );

int main()
{
  	const char* teste[][2] =
      {
          { "azul", "azul" },
          { "zul", "azul" },
          { "azul", "zul" },
          { "", "azul" },
          { "", "" },
          { "uma string", "uma string" },
          { "uma string", "uma strinG" },
          { "coisa", "" }
       };

    int n = sizeof(teste)/(2 * sizeof(char*));

    testaF( n, teste,
        comparaString2, 
        "Usando funcao iterativa");

    testaF( n, teste,
        comparaString, 
        "Usando funcao original");

     testaF( n, teste,
        comparaString3, 
        "Usando funcao recursiva");

  	return 0;
};

int comparaString (char str1[100],char str2[100])
{
		int i,j,cont=0;
		
		for(i=0;str1[i]!=0;i++)
		{
			for(j=0;str2[j]!=0;j++)
			{
				if(str1[i]==str2[j])
				{
					cont++;
				}
			}
		}
	
		return cont;
}

int comparaString2 (char* str1, char* str2 )
{
    while( *str1 != 0 )
    {
        if ( *str2 == 0 ) return 0;
        if( *str1 != *str2 ) return 0;
        str1+=1; str2+=1;
    };
    return ( *str2 == 0);
};  

int comparaString3 ( char* str1, char* str2 )
{
    if ( *str1 != 0 )
    {
        if ( *str2 == 0 )       return 0;
        if ( *str1 == *str2 )   return comparaString3( ++str1, ++str2 );
        return 0;
    }
    else
        return ( *str2 == 0 );
};  

void testaF(
    unsigned n, const char* teste[][2],
    int(*f)(char*,char*), const char* msg)
{
   	if( msg != NULL )
        printf("\n\n%s\n\n\t==> %d testes:\n\n",msg,n);
    else
   	    printf ( "\n\n==> %d testes:\n\n", n );

 	for (int i=0;i<n;i++)
    {
         printf("\
%02d/%02d  \"%s\" vs \"%s\" retornou %d\n",
        1+i,n, teste[i][0], teste[i][1], 
        f( (char*) teste[i][0], (char*) teste[i][1] ) );
      }; // for()

};

 

 

 

 

Só a minha iterativa que funcionou

Link para o comentário
Compartilhar em outros sites

18 minutos atrás, Comunista.RJ disse:

arquivos ".c" não aceitam declarar a variável dentro do for

 

Claro que é.

 

Como te disse, essa era uma coisa que se esperava em C desde os anos 70 e só foi para a norma no final dos 80. Mas foi no final da década de 80, 40 a nos atrás. É como está no exemplo que te mostrei. Desde então é prática comum e recomendada em todo o planeta C. 

 

Em C++ isso foi estendido em 2017 para permitir declarações dentro de if e switch. Eu postei uns exemplos aqui outro dia. Acho que dá pra pesquisar no conteúdo no meu perfil aqui. Se eu mexer em algum programa significativo que eu possa postar eu faço isso.

 

Em relação a C estamos falando apenas de coisas como 
 

int i = 300;
for( i=0; i<N; i+= 1){};

 

serem condenadas e proibidas em empresas e escolas e estarem em todos os guias de boas práticas e códigos de conduta em codificação que já vi desde que isso se tornou possível.


É só isso:

 

int i = 300;
for(int i=0; i<N; i+= 1){};

 

O primeiro i é global à função em que está declarado. O escopo --- scope -- do segundo é restrito ao { } do for em que foi declarado. E isso é muito importante. Em especial variáveis com nomes singelos como i, aux, opt... Isso acaba sendo reusado sem querer em outro lugar e achar um erro desses é um pesadelo. 

 

Sobre as letras e o "desafio"

 

Essa é a noção matemática de conjunto com repetição, e assim define bem a questão. Claro que a noção de conjunto como implementada por exemplo em C++ set (classe) e java Set (interface) é mais útil e consideraria cada elemento que aparece nas duas listas uma única vez.

Mas implementar isso recursivamente aqui em C seria chatinho: é preciso olhar para trás e saber se a letra já foi considerada. Fiquei pensando nisso no café há pouco. :)  É um problema interessante porque salvar estado em funções recursivas é sempre difícil. 

 

Com essa liberdade o desafio é mais simples. 

Link para o comentário
Compartilhar em outros sites

@arfneto Eu sei. No DEVC++, se você gravar o arquivo como .c, ele não aceita declarar dentro do for.

 

"50    2    D:\desafio.c    [Error] 'for' loop initial declarations are only allowed in C99 or C11 mode"

@arfneto

int comparaString (char* str1,char* str2)
{
        int i,j,cont=0,CONT=0;
        
        for(i=0;str1[i]!=NULL;i++)
        {
            for(j=0;str2[j]!=NULL;j++)
            {
                if(str1[i]==str2[j])
                {
                    cont++;break;
                }
            }
        }
        
        for(i=0;str2[i]!=NULL;i++)
        {
            for(j=0;str1[j]!=NULL;j++)
            {
                if(str2[i]==str1[j])
                {
                    CONT++;break;
                }
            }
        }
        
        if (CONT>cont)
        {
            return cont;
        }
        else
        
        {
            return CONT;
        }
}

 

Não conta caracter repetido

Link para o comentário
Compartilhar em outros sites

9 horas atrás, Comunista.RJ disse:

No DEVC++, se você gravar o arquivo como .c, ele não aceita declarar dentro do for

 

Desista. Eu sei do que estou falando. Uso isso desde os anos '70. Mas vou te explicar.

 

Dev-C++ não é um ambiente sério de desenvolvimento. A configuração inicial dele é usar a versão de C de 1988 e a de C++ de 98. Fuja disso. Até onde eu sei esse ambiente sequer tem a condição de parar um programa de teste na console ao final. O único caso que eu vi até hoje. Eu não conhecia e descobri nesse forum. Uma piada ter que mudar o código para parar o programa :D quando roda dentro de um IDE. Caso único.

 

Qualquer ambiente é melhor que esse Dev-C++. Provavelmente o melhor de todos é o CLion que por coincidência até anuncia aqui neste forum às vezes. A JetBrains sabe escrever essas coisas. Mas tem o Eclipse, o NetBeans, o Visual Studio... O Visual Studio Code é sensacional: roda em qualquer coisa e permite que você por exemplo teste um programa no Linux sem sair da mesa onde está o desktop Windows. Fechar o projeto e abrir outro em javascript no Windows e fechar esse e entrar no debugger em uma aplicação em Python no Linux. Sem sair do contexto. O mesmo editor. Linux ou Windows. E pode emular os comandos de qualquer editor, como o pai de todos, o vi

 

E sempre pode usar make, CMake e um bom editor de texto como o sublime text ou o Atom. Ou o vi no Linux. Mas é claro que pode editar um programa no bloco de notas do Windows ou no MS Word.
 

Desde 1989

O tempo passou. C evoluiu muito. Muito mesmo. E C++ também. Se ficar nos padrões de décadas atrás claro que vai perder em produtividade e recursos. E não vai entender os programas modernos.

 

O que fazer

Agora que sabe o que está errado e se não quer abandonar esse IDE vá nas configurações disso e inclua ao menos
 

-std=c17 -Wall -Wextra -g


nas configurações para C. 

 

9 horas atrás, Comunista.RJ disse:

"50    2    D:\desafio.c    [Error] 'for' loop initial declarations are only allowed in C99 or C11 mode"

 

Pois é. Estou digitando esse post no final de 2020. Supondo que C99 se refira a 1999 ___ e se refere ___ e C11 a 2011 ___ e se refere ___ não seria razoável estar usando um modo desses ou mesmo um mais recente? Tem ideia do quanto essas linguagens evoluiram nesse período? Muito. E a vida segue: O comitê ISO C++ liberou uma versão C++20. Nesse ano.  Use -std=c++20 ou ao menos -std=c++17 se seu compilador for antigo, para não ficar à margem do progresso.

 

Considere esse sofisticado programa desafio.c
 

#include<stdio.h>
int main(void)
{	// isso tambem nao tinha
    for ( int i=0;;){};
}

 

E veja o que acontece:

 

image.png.23c1a784c8466c69a7922b75cae6a711.png

 

Espero que tenha entendido.

 

E veja que o compilador até diz pra você o que fazer...

 

Link para o comentário
Compartilhar em outros sites

@arfneto Acho que você não entendeu, mas deixa prá lá.

 

É só salvar como .cpp que funciona.

 

Não estou preocupado com essas coisas agora.

 

Sei todas as "regras de etiqueta" dos códigos.

 

Perda de tempo... estou queimando os neurônios aqui ainda com a função recursiva! KKKK

5 minutos atrás, Comunista.RJ disse:

@arfneto Acho que você não entendeu, mas deixa prá lá.

 

É só salvar como .cpp que funciona.

 

Não estou preocupado com essas coisas agora.

 

Sei todas as "regras de etiqueta" dos códigos.

 

Perda de tempo... estou queimando os neurônios aqui ainda com a função recursiva! KKKK

Por exemplo, eu uso operador ternário nos meus códigos, você não. Estou escrevendo para tentar entender a recursividade.

E por fim, obrigado por se disponibilizar a ajudar.

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

25 minutos atrás, Comunista.RJ disse:

É só salvar como .cpp que funciona

 

Não. Não funciona. C++ é outra linguagem e algumas coisas são muito diferentes. E um enorme número delas não existe em C. Apenas faça o que eu disse; é uma linha só. Uma vez só.

 

26 minutos atrás, Comunista.RJ disse:

Perda de tempo...

 

Não, não é: nessas décadas a linguagem melhorou muito. E isso quer dizer que leva menos tempo para fazer as coisas, receber seu dinheiro, entregar seu trabalho ou mesmo codificar seu desafio.

 

27 minutos atrás, Comunista.RJ disse:

Por exemplo, eu uso operador ternário nos meus códigos, você não

 

Não entendi. 

 

28 minutos atrás, Comunista.RJ disse:

estou queimando os neurônios aqui ainda com a função recursiva!

 

Copie da que eu postei. É quase igual. Só muda o loop interno.

Link para o comentário
Compartilhar em outros sites

@arfneto funciona filho, eu faço isso. rs

 

Ternário:
cont >= 0 ? aux++ : aux=0;

ao invés de

if (cont > = 0) aux++; else aux=0;

@arfneto "Copie da que eu postei. É quase igual. Só muda o loop interno."

Não funciona. a sua é para string; não consegui adaptar para caracteres. Isso que estou tentando.

Link para o comentário
Compartilhar em outros sites

12 minutos atrás, Comunista.RJ disse:

funciona filho, eu faço isso. rs

desista. Não é o caso. Muitas coisas em C não são válidas em C++. E tem o contrário: um universo de coisas que existem em um código cpp não existe em C.

 

O fato de funcionar para códigos que você escreveu, escritos em C dos anos 80, não leva a nada. As linguagens são absolutamente diferentes. Nem vou escrever agora um código pra te mostrar porque hoje o tempo é pouco.

 

15 minutos atrás, Comunista.RJ disse:

Ternário:

 

Eu sei exatamente o que é. E não tem nada de especial. Usaria se tivesse motivo. "Meus códigos" não são postados aqui. Apenas em meu tempo livre escrevo algo se acho que posso ajudar alguém. E aí em geral escrevo sobre o código de outros, como fiz com o seu.

Operadores ternários são difíceis de ler e não fazem sentido em um forum pra iniciantes. Não porque seja um conceito avançado. Apenas porque é difícil de ler e fácil de errar.

 

18 minutos atrás, Comunista.RJ disse:

Não funciona. a sua é para string; não consegui adaptar para caracteres

 

Não existe nada "para string" em C. string é char*. Uma série de letrinhas onde por convenção a última é um zero. Depois te mostro uma opção que funciona e vai ver que é quase igual aquela.

Link para o comentário
Compartilhar em outros sites

2 horas atrás, Comunista.RJ disse:

existe sim, são só jogo de palavras usados para compreensão do que se quer

 

Como queira. Mas o jogo de palavras não vai mudar a realidade. Pode parecer diferente apenas. Admiro a fé e a teimosia. Considere esse programa em C
 

#include<stdio.h>
int main(void)
{
    const char* class = "O que e real afinal?\n";
    printf("%s",class);
}

 

Que mostra "O que e real afinal?"na tela:

 

image.png.31388a468362d35ae4baa7a2d51a3913.png

 

Mude o nome dele para eusei.cpp e rode na sua maquina...
 

image.png.8e460117b8114fa6ce9a8b87cefc833f.png

 

Oh... Estraguei a surpresa... :D 

 

De volta ao seu desafio, no café pós almoço, porque achei divertido:
 

Como eu imaginava, uma implementação de comparaString() recursiva ___  e agora com a definição que você afinal forneceu ___ não difere muito do código que te mostrei. E é mais simples, porque a segunda string é só uma tabela de referência nesse caso. Veja:

 

int comparaString(const char* str1, const char* str2)
{
    static unsigned      mmr[256];
    static char   run = 0;
    static char* origem = NULL;
    char c = 0;

    if (!run)
    {
        run = 2;
        memset(mmr, 0, sizeof(mmr));
        origem = (char*)str1;
    }   // if()

    if (*str1 == 0)
    {   // fim da linha
        unsigned cnt_geral = 0;
        for (unsigned i = 0; i < 255; i += 1)
        {
            c = mmr[i];
            if (c != 0)
            {
                cnt_geral += c;
            };  // if()
        };
        run = 0;
        return cnt_geral;
    }

    const char* p = str2;
    while (*p != 0)
    {
        if (*str1 == *p) mmr[*str1] += 1;
        p++;
    };  // while()
    return comparaString(++str1, str2);
};

 

Usando a mesma estrutura de teste que te mostrei antes, porque tempo é valioso:

 

int main()
{
    const char* teste[][2] =
    {
        { "azul", "aazzuull" },
        { "azul", "azul" },
        { "azul", "" },
        { "", "azul" },
        { "uma string", "uma string" }
    };

    int n = sizeof(teste) / (2 * sizeof(char*));
    testaF(n, teste,
        comparaString,
        "Usando funcao recursiva");

    return 0;
};

 

Mostra 

 

Usando funcao recursiva

        ==> 5 testes:

01/05  "azul" vs "aazzuull" retornou 8
02/05  "azul" vs "azul" retornou 4
03/05  "azul" vs "" retornou 0
04/05  "" vs "azul" retornou 0
05/05  "uma string" vs "uma string" retornou 10



 

Implementando o mais significativo: filtrando as letras de str2 que estão em str1, esquecendo aquela "colher de chá" dada pela alínea (ii) do seu enunciado


 

Citação

ii. If the same character appears n times in a given string, it will not be considered an error if your solution counts this character n times;


porque provavelmente acharam que ficaria muito difícil (não fica, a menos que fosse retornar char* com a string resultante):

 

Com umas poucas linhas a mais para imprimir o resultado, no if(mostra)

 

int comparaString(const char* str1, const char* str2)
{
    static unsigned      mmr[256];
    static char   run = 0;
    static char* origem = NULL;
    char c = 0;
    char mostra = 1;

    if (!run)
    {
        run = 2;
        memset(mmr, 0, sizeof(mmr));
        origem = (char*)str1;
    }   // if()

    if (*str1 == 0)
    {   // fim da linha
        unsigned cnt_geral = 0;
        unsigned cnt_unico = 0;
        for (unsigned i = 0; i < 255; i += 1)
        {
            c = mmr[i];
            if (c != 0)
            {
                cnt_geral += c;
                cnt_unico += 1;
            };  // if()
        };
        if (mostra)
        {
            char* intersect = (char*)malloc(1 + cnt_unico);
            char* pI = intersect;
            fprintf(stderr, "\n\n\
String1:\t\"%s\"\n\
String2:\t\"%s\"\n\n\
Letra    Hexa   Ocorrencias\n",
origem, str2);
            for (int i = 0; i < 256; i += 1)
            {
                if (mmr[i] != 0)
                {
                    fprintf(stderr, " '%c'      %X     %8d\n",
                        i, i, mmr[i]);
                    *pI = i; pI++;
                };  // if()
            };  // for()
            *pI = 0;
            fprintf(stderr, "\
\n=> %d letras duplicadas. Valores unicos: %d\n",
cnt_geral, cnt_unico);
            // mostra o que seria a interseccao
            if( cnt_unico > 0 )
                fprintf(stderr, "\
\n=> As letras '%s' aparecem nas duas strings\n\n",
                intersect);
            free(intersect);
        };  // if()
        run = 0;
        return cnt_geral;
    }

    const char* p = str2;
    while (*p != 0)
    {
        if (*str1 == *p) mmr[*str1] += 1;
        p++;
    };  // while()
    return comparaString(++str1, str2);
};

 

E aí mostra para o primeiro conjunto de dados por exemplo:
 

String1:        "azul"
String2:        "aazzuull"

Letra    Hexa   Ocorrencias
 'a'      61            2
 'l'      6C            2
 'u'      75            2
 'z'      7A            2

=> 8 letras duplicadas. Valores unicos: 4

=> As letras 'aluz' aparecem nas duas strings

01/05  "azul" vs "aazzuull" retornou 8

 

E aí está a string str1 "filtrada" pela str2.

  • E também as letras e o contador de repetições.
  • E o código em hexa da letra porque espaço por exemplo não dá pra enxergar
  • E também o total de valores únicos.

Eis a saída do mesmo teste para as outras strings
 

Spoiler



Usando funcao recursiva

        ==> 5 testes:



String1:        "azul"
String2:        "aazz uull"

Letra    Hexa   Ocorrencias
 'a'      61            2
 'l'      6C            2
 'u'      75            2
 'z'      7A            2

=> 8 letras duplicadas. Valores unicos: 4

=> As letras 'aluz' aparecem nas duas strings

01/05  "azul" vs "aazz uull" retornou 8


String1:        "azul"
String2:        "azul"

Letra    Hexa   Ocorrencias
 'a'      61            1
 'l'      6C            1
 'u'      75            1
 'z'      7A            1

=> 4 letras duplicadas. Valores unicos: 4

=> As letras 'aluz' aparecem nas duas strings

02/05  "azul" vs "azul" retornou 4


String1:        "azul"
String2:        ""

Letra    Hexa   Ocorrencias

=> 0 letras duplicadas. Valores unicos: 0
03/05  "azul" vs "" retornou 0


String1:        ""
String2:        "azul"

Letra    Hexa   Ocorrencias

=> 0 letras duplicadas. Valores unicos: 0
04/05  "" vs "azul" retornou 0


String1:        "uma string"
String2:        "uma strinG"

Letra    Hexa   Ocorrencias
 ' '      20            1
 'a'      61            1
 'i'      69            1
 'm'      6D            1
 'n'      6E            1
 'r'      72            1
 's'      73            1
 't'      74            1
 'u'      75            1

=> 9 letras duplicadas. Valores unicos: 9

=> As letras ' aimnrstu' aparecem nas duas strings

05/05  "uma string" vs "uma strinG" retornou 9

 

 

E o programa final. É o mesmo de antes, claro. Só recortar e colar

 

Spoiler

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

int     comparaString(const char*, const char*);

void testaF(unsigned, const char* [][2],
    int(*)(const char*, const char*), const char*);

int main()
{
    const char* teste[][2] =
    {
        { "azul", "aazz uull" },
        { "azul", "azul" },
        { "azul", "" },
        { "", "azul" },
        { "uma string", "uma strinG" }
    };

    int n = sizeof(teste) / (2 * sizeof(char*));
    testaF(n, teste,
        comparaString,
        "Usando funcao recursiva");

    return 0;
};


int comparaString(const char* str1, const char* str2)
{
    static unsigned      mmr[256];
    static char   run = 0;
    static char* origem = NULL;
    char c = 0;
    char mostra = 1;

    if (!run)
    {
        run = 2;
        memset(mmr, 0, sizeof(mmr));
        origem = (char*)str1;
    }   // if()

    if (*str1 == 0)
    {   // fim da linha
        unsigned cnt_geral = 0;
        unsigned cnt_unico = 0;
        for (unsigned i = 0; i < 255; i += 1)
        {
            c = mmr[i];
            if (c != 0)
            {
                cnt_geral += c;
                cnt_unico += 1;
            };  // if()
        };
        if (mostra)
        {
            char* intersect = (char*)malloc(1 + cnt_unico);
            char* pI = intersect;
            fprintf(stderr, "\n\n\
String1:\t\"%s\"\n\
String2:\t\"%s\"\n\n\
Letra    Hexa   Ocorrencias\n",
origem, str2);
            for (int i = 0; i < 256; i += 1)
            {
                if (mmr[i] != 0)
                {
                    fprintf(stderr, " '%c'      %X     %8d\n",
                        i, i, mmr[i]);
                    *pI = i; pI++;
                };  // if()
            };  // for()
            *pI = 0;
            fprintf(stderr, "\
\n=> %d letras duplicadas. Valores unicos: %d\n",
cnt_geral, cnt_unico);
            // mostra o que seria a interseccao
            if( cnt_unico > 0 )
                fprintf(stderr, "\
\n=> As letras '%s' aparecem nas duas strings\n\n",
                intersect);
            free(intersect);
        };  // if()
        run = 0;
        return cnt_geral;
    }

    const char* p = str2;
    while (*p != 0)
    {
        if (*str1 == *p) mmr[*str1] += 1;
        p++;
    };  // while()
    return comparaString(++str1, str2);
};  // comparaString()


void testaF(
    unsigned n, const char* teste[][2],
    int(*f)(const char*, const char*), const char* msg)
{
    if (msg != NULL)
        printf("\n\n%s\n\n\t==> %d testes:\n\n", msg, n);
    else
        printf("\n\n==> %d testes:\n\n", n);

    for (unsigned i = 0; i < n; i++)
    {
        printf("\
%02d/%02d  \"%s\" vs \"%s\" retornou %d\n",
1 + i, n, teste[i][0], teste[i][1],
f((char*)teste[i][0], (char*)teste[i][1]));
    }; // for()

};

 

 

Repito: usar recursão nesse caso é uma b0b@g3m. É muito lerdo e nada eficiente. Serve apenas para reforçar algum conceito, como dificuldade em recursão, claro. Ou alguma aposta ou desafio mesmo. 

 

 

Link para o comentário
Compartilhar em outros sites

46 minutos atrás, Comunista.RJ disse:

Não vale porque tem laço "for". Vou tentar por aqui, se eu conseguir eu posto. Abraços

? Deve estar brincando

 

Recursividade é só isso: Uma função ou algoritmo que de algum modo chama a si mesmo. Só isso. Não há desafio ou forum que mude isso.

 

Em geral a recursão acontece no início ou no final do processo. Nesse caso no final.

 

A própria recursão é um for(), e vai entender isso lendo o código. E como um for seria mais eficiente. como já expliquei e você pode medir para provar. Também mostrei como medir isso nessa semana em outro post

 

É o seu desafio, afinal. Espero que tenha entendido ao menos o mecanismo e as coisas que te expliquei. Atualize seu IDE. 89 passou há muito.

 

Deve servir para outros ao menos

 

Abraço

Link para o comentário
Compartilhar em outros sites

1 minuto atrás, arfneto disse:

? Deve estar brincando

 

Recursividade é só isso: Uma função ou algoritmo que de algum modo chama a si mesmo. Só isso. Não há desafio ou forum que mude isso.

 

Em geral a recursão acontece no início ou no final do processo. Nesse caso no final.

 

A própria recursão é um for(), e vai entender isso lendo o código. E como um for seria mais eficiente. como já expliquei e você pode medir para provar. Também mostrei como medir isso nessa semana em outro post

 

É o seu desafio, afinal. Espero que tenha entendido ao menos o mecanismo e as coisas que te expliquei. Atualize seu IDE. 89 passou há muito.

 

Deve servir para outros ao menos

 

Abraço

 

2 minutos atrás, arfneto disse:

? Deve estar brincando

 

Recursividade é só isso: Uma função ou algoritmo que de algum modo chama a si mesmo. Só isso. Não há desafio ou forum que mude isso.

 

Em geral a recursão acontece no início ou no final do processo. Nesse caso no final.

 

A própria recursão é um for(), e vai entender isso lendo o código. E como um for seria mais eficiente. como já expliquei e você pode medir para provar. Também mostrei como medir isso nessa semana em outro post

 

É o seu desafio, afinal. Espero que tenha entendido ao menos o mecanismo e as coisas que te expliquei. Atualize seu IDE. 89 passou há muito.

 

Deve servir para outros ao menos

 

Abraço

@arfneto Não vale porque tem laço "for". Vou tentar por aqui, se eu conseguir eu posto. Abraços.

 

 

Você que não entendeu muito bem, mas deixa pra lá. Vou tentar sozinho ou esperar alguém que me ajude. Quando eu conseguir eu mostro aqui. Até a próxima!

Link para o comentário
Compartilhar em outros sites

21 minutos atrás, Comunista.RJ disse:

Você que não entendeu muito bem, mas deixa pra lá

Explique. Pode me ajudar a entender. E a outros.

Todo loop é uma recursão. Toda recursão é um loop. Veja no exemplo os loop e considere o seu enunciado e poderá excluir os loops. Poste algum código.

 

O que faz você achar que um for() tenha algo a ver ou contra o fato de uma função cuja única função que chama é a si mesma, deixe de ser recursiva?

Link para o comentário
Compartilhar em outros sites

Em 12/11/2020 às 01:35, Comunista.RJ disse:


#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

int comparaString (char str1[100],char str2[100]);

int main(void)
	{
		int cont=0;
		
		char str1[100],str2[100];
		
		system("cls");
		fflush(stdin);
		printf("\nString1...:\n");
		gets(str1);
		system("cls");
		fflush(stdin);
		printf("\nString2...:\n");
		gets(str2);
		
		cont=comparaString (str1,str2);
		
		printf("\nExistem %i caracteres comuns entre as duas strings\n",cont);
		
		return 0;
	}
	
int comparaString (char str1[100],char str2[100])
{
		int i,j,cont=0;
		
		for(i=0;str1[i]!=NULL;i++)
		{
			for(j=0;str2[j]!=NULL;j++)
			{
				if(str1[i]==str2[j])
				{
					cont++;
				}
			}
		}
		
		return cont;
}

Como fazer de forma totalmente recursiva?

Eu mesmo consegui me responder, segue:
 

 

Link para o comentário
Compartilhar em outros sites

  • Solução
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

int comparaString2(char str1,char* str2);

int comparaString (char* str1,char* str2);

int main(void)
 {
  int cont=0;
  
  char str1[100],str2[100];
  
  fflush(stdin);
  printf("\nString1...:\n");
  gets(str1);

  fflush(stdin);
  printf("\nString2...:\n");
  gets(str2);

  cont=comparaString (str1,str2);

  printf("\nExistem %i caracteres comuns entre as duas strings\n",cont);

  return 0;
 }

int comparaString (char* str1,char* str2)
 {
  if (!str1[0])
  {
   return 0;
  }

  return(comparaString2(str1[0],str2)+comparaString(++str1,str2));

  return (comparaString (++str1,str2));

 }

int comparaString2(char str1,char* str2)
 {
  if (!str2[0])
  {
   return 0;
  }

  if (str2[0]==str1)
  {
   return (1+comparaString2(str1,++str2));
  }

  else

  return comparaString2(str1,++str2);
 }

Solução!

Link para o comentário
Compartilhar em outros sites


Testou mesmo essa solução anes de marcar como tal?🤔
 

19 horas atrás, arfneto disse:

Explique. Pode me ajudar a entender. E a outros.

Todo loop é uma recursão. Toda recursão é um loop. Veja no exemplo os loop e considere o seu enunciado e poderá excluir os loops. Poste algum código.

 

O que faz você achar que um for() tenha algo a ver ou contra o fato de uma função cuja única função que chama é a si mesma, deixe de ser recursiva?

 

Pois é. Você respondeu:

 

13 horas atrás, Comunista.RJ disse:

Eu mesmo consegui me responder, segue

 

Para responder a si mesmo não se usa um forum. E não foi você que perguntou nesse caso: eu perguntei qual o sentido da afirmação
 

19 horas atrás, Comunista.RJ disse:

Não vale porque tem laço "for". Vou tentar por aqui, se eu conseguir eu posto. Abraços.

 

Você não precisa responder nem para mim nem para o forum, claro. Mas postar uma resposta que encontrou para si mesmo é curioso ;) 

 

A pergunta era "que tem a ver um for em uma função recursiva com o fato de ela ser recursiva ou não? Que significa a expressão "não vale" por exemplo?

 

E a sua solução

 

Muito bem. Parabéns. E já foi marcada como solução! É certo que foi marcada pelo próprio autor, você mesmo, mas está claro lá que é a solução. ✔️

 

E a solução resolve?
 

Curiosamente eu te mostrei um programa e uma função para testar isso e expliquei até porque usar. E você preferiu claro seguir seu caminho resoluto e que levou à solução final ótima e elegante.

 

No entanto rodando o mesmo programa que te mostrei e você poderia ter copiado se vê na tela:
 



A versao que "nao vale" segundo voce

        ==> 5 testes:

01/05  "azul" vs "aazz uull" retornou 8
02/05  "azul" vs "azul" retornou 4
03/05  "azul" vs "" retornou 0
04/05  "" vs "azul" retornou 0
05/05  "uma string" vs "uma strinG" retornou 9


A versao "Solucao" e "resposta" segundo voce

        ==> 5 testes:

01/05  "azul" vs "aazz uull" retornou 6
02/05  "azul" vs "azul" retornou 3
03/05  "azul" vs "" retornou 0
04/05  "" vs "azul" retornou 0
05/05  "uma string" vs "uma strinG" retornou 8

 

E os resultados não batem.

 

Você pode responder qual está correto apenas lendo acima ou rodando esse programa aqui abaixo:
 

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

int     comparaString(const char*, const char*);
int     comparaString2(const char*, const char*);
int     comparaStringA(const char*, const char*);

void testaF(unsigned, const char* [][2],
    int(*)(const char*, const char*), const char*);

int main()
{
    const char* teste[][2] =
    {
        { "azul", "aazz uull" },
        { "azul", "azul" },
        { "azul", "" },
        { "", "azul" },
        { "uma string", "uma strinG" }
    };

    int n = sizeof(teste) / (2 * sizeof(char*));

    testaF(n, teste,
        comparaStringA,
        "A versao que \"nao vale\" segundo voce");


    testaF(n, teste,
        comparaString,
        "A versao \"Solucao\" e \"resposta\" segundo voce");

    return 0;
};


void        testaF(
    unsigned n, const char* teste[][2],
    int(*f)(char*, char*), const char* msg)
{
    if (msg != NULL)
        printf("\n\n%s\n\n\t==> %d testes:\n\n", msg, n);
    else
        printf("\n\n==> %d testes:\n\n", n);

    for (unsigned i = 0; i < n; i++)
    {
        printf("\
%02d/%02d  \"%s\" vs \"%s\" retornou %d\n",
1 + i, n, teste[i][0], teste[i][1],
f((char*)teste[i][0], (char*)teste[i][1]));
    }; // for()
};

 

Ou teste a "solução" digitando no teclado os valores um por um, do modo bem moderno. 

 

Mas pode usar a função que eu postei no tópico #2 e o programa de teste que eu coloquei lá junto para te ajudar. Ela serve apara testar qualquer número de funções.

 

Ainda sobre a solução


O erro que cometeu é o clássico one-off e é o trivial para pegar quando

  • se testa mecanicamente
  • quando tem um patrão ou orientador rigoroso.
  • quanto se tem menos auto-confiança e acha que é melhor testar mais

Acredito que possa fazer funcionar ainda, mas é uma ideia mínima apoiada em uma "muleta" deixa na alínea (ii). O alvo do seu  desafio é:

 

Desafio

 

Citação

Develop a recursive function that determines the number of common characters between two strings s1 and s2.

 

Em português: 
 

Desenvolver uma função recursiva que determine o número de caracteres em comum entre duas string s1 e s2
 

E tem a "colher de chá" 

Citação


 ii. If the same character appears n times in a given string, it will not be considered an error if your solution counts this character n times;


 

Em português: 

ii. Se a mesma letra aparecer N vezes em uma certa string não será considerado um erro se sua solução acumular essa letra N vezes

 

E a restrição:
 

Citação

iii. If your solution is broken down into more than one function (so that the main one - which solves the proposed problem - calls other helpers), all functions must be recursive;


Em português: 
 

Se sua solução for dividida em mais de uma função (de modo que a função principal, que resolve o problema proposto - chama outras funções auxiliares), todas as funções devem ser recursivas

 

Uma vez que funcione você terá feito o mínimo do mínimo.

 

 

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