Aide - Programme C++
Résolu
May
-
May -
May -
Bonjour! Je suis débutante en C++ et j'ai de la misère à faire un exercice de programmation (je ne comprends pas pourquoi ça ne fonctionne pas, même si mon compilateur ne me renvoie aucune erreur). Voici ce que dit l'exercice :
Écrire une fonction dont le prototype est int incluse (char chaine1[] , char chaine2[]) ; . La fonction incluse() retourne le nombre d'occurence de chaine1 dans chaine2. La fonction incluse peut être définie par plusieurs fonctions.
Exemple: chaine1 = 'Bonjour'
chaine2 = 'jour'
résultat = 1
Voici ce que j'ai fait :
#include <iostream>
#include <string.h>
using std::cout ;
using std::cin ;
using std::endl ;
int incluse (char chaine1[] , char chaine2[]) {
int compteur = 0 ;
int i ;
int j = 0 ;
for (i=0 ; i<strlen(chaine2) ; i++) {
while (j<strlen(chaine1)) {
if (chaine1[j] == chaine2[i]) {
j++ ;
}}
if (j==strlen(chaine1)) {
compteur++;
}
}
return compteur ;
}
main () {
char chaine1[100] ;
char chaine2[100] ;
int compteur ;
cout << "Entrer une chaine de caracteres : \n" ;
cin >> chaine2 ;
cout << "Voici la chaine de caracteres que vous avez entre : \n" << chaine2 <\
< endl ;
cout << "Entrer une sequence de caracteres a rechercher : \n" ;
cin >> chaine1 ;
compteur = incluse (chaine1 , chaine2) ;
cout << "Le nombre d'occurence de la 1re chaine dans la 2e est : \n" << compt\
eur << endl ;
return 0 ;
}
Aidez-moi je vous en prie! Merci beaucoup pour votre aide!
Écrire une fonction dont le prototype est int incluse (char chaine1[] , char chaine2[]) ; . La fonction incluse() retourne le nombre d'occurence de chaine1 dans chaine2. La fonction incluse peut être définie par plusieurs fonctions.
Exemple: chaine1 = 'Bonjour'
chaine2 = 'jour'
résultat = 1
Voici ce que j'ai fait :
#include <iostream>
#include <string.h>
using std::cout ;
using std::cin ;
using std::endl ;
int incluse (char chaine1[] , char chaine2[]) {
int compteur = 0 ;
int i ;
int j = 0 ;
for (i=0 ; i<strlen(chaine2) ; i++) {
while (j<strlen(chaine1)) {
if (chaine1[j] == chaine2[i]) {
j++ ;
}}
if (j==strlen(chaine1)) {
compteur++;
}
}
return compteur ;
}
main () {
char chaine1[100] ;
char chaine2[100] ;
int compteur ;
cout << "Entrer une chaine de caracteres : \n" ;
cin >> chaine2 ;
cout << "Voici la chaine de caracteres que vous avez entre : \n" << chaine2 <\
< endl ;
cout << "Entrer une sequence de caracteres a rechercher : \n" ;
cin >> chaine1 ;
compteur = incluse (chaine1 , chaine2) ;
cout << "Le nombre d'occurence de la 1re chaine dans la 2e est : \n" << compt\
eur << endl ;
return 0 ;
}
Aidez-moi je vous en prie! Merci beaucoup pour votre aide!
A voir également:
- Aide - Programme C++
- Programme demarrage windows - Guide
- Message programmé iphone - Guide
- Programme word gratuit - Guide
- Mettre en veille un programme - Guide
- Cette action ne peut pas être réalisée car le fichier est ouvert dans un autre programme - Guide
16 réponses
Tu peux déjà rajouter le int devant ton main :
Actuellement tu utilises string.h qui est un header C. Je te propose d'utiliser plutôt les string du C++ qui sont nettement plus pratique :
//#include <string.h>
#include <string>
Les strings s'appèlent std::string (de même que les sorties et entrées standards sont std::cerr, std::cout, std::cin), donc si tu es dans un fichier .cpp, tu peux omettre le std:: en mettant :
Le prototype de estIncluse devient :
L'intérêt des string est qu'elles proposent pas mal de fonctions sympatiques (recherche d'une sous-chaine, extraction d'un morceau de chaine, taille, opérateur d'égalité, d'affectation...)
Ensuite comme tu le sais sans doute, en C et en C++ les paramètres sont recopiés en mémoire. Dans ton cas ce sera les deux chaînes complètes qui seront donc recopiées ! Ceci est d'autant plus gênant que les structures passés en paramètres sont grandes. On utilise donc des pointeurs, ou mieux, des références :
Tu passes juste l'adresse en paramètre ce qui est donc plus rapide puisque tu ne recopies pas toute la chaîne. D'autre part ces chaînes ne varient pas à l'intérieur de la fonction est incluse. On peut donc garantir leur constance dans le prototype :
Ok maintenant il faut corriger deux trois choses, notamment la longueur d'une chaine s'obtient par :
Un std::size_t est en réalité un unsigned int.
Pour extraire le morceau de chaîne qui nous intéresse on va utiliser la fonction substr :
https://en.cppreference.com/w/cpp/string/basic_string/substr
Tu noteras que i est défini dans le for ce qui signifie que cette variable n'existera que tant qu'on sera dans le for. Outre le fait que tu gagnes en mémoire, ça évite certaines erreur. Je te conseille donc de fonctionner comme ça par la suite. Ceci dit ça ne marche qu'en C++.
Je n'ai pas compilé le code donc il comporte peut être quelques erreurs, mais je te laisse corriger, c'était juste pour te donner le début.
On peut encore améliorer le programme : la copie de sous_chaine2 fait perdre "beaucoup de temps", donc plutôt que d'utiliser substr, ont pourrait plutôt utiliser la méthode find() :
https://en.cppreference.com/w/cpp/string/basic_string/find
... et à chaque fois qu'une occurence de chaine1 est trouvée dans chaine2, déplacer le début de chaine2... Idéalement c'est comme ça qu'il faudrait faire. Je te laisse expérimenter tout ça ;)
Bonne chance
int main(){ ... }
Actuellement tu utilises string.h qui est un header C. Je te propose d'utiliser plutôt les string du C++ qui sont nettement plus pratique :
//#include <string.h>
#include <string>
Les strings s'appèlent std::string (de même que les sorties et entrées standards sont std::cerr, std::cout, std::cin), donc si tu es dans un fichier .cpp, tu peux omettre le std:: en mettant :
using namespace std;
Le prototype de estIncluse devient :
int incluse (std::string chaine1 ,std::string chaine2){ ... }
L'intérêt des string est qu'elles proposent pas mal de fonctions sympatiques (recherche d'une sous-chaine, extraction d'un morceau de chaine, taille, opérateur d'égalité, d'affectation...)
Ensuite comme tu le sais sans doute, en C et en C++ les paramètres sont recopiés en mémoire. Dans ton cas ce sera les deux chaînes complètes qui seront donc recopiées ! Ceci est d'autant plus gênant que les structures passés en paramètres sont grandes. On utilise donc des pointeurs, ou mieux, des références :
int incluse (std::string & chaine1 ,std::string & chaine2){ ... }
Tu passes juste l'adresse en paramètre ce qui est donc plus rapide puisque tu ne recopies pas toute la chaîne. D'autre part ces chaînes ne varient pas à l'intérieur de la fonction est incluse. On peut donc garantir leur constance dans le prototype :
int incluse (const std::string & chaine1 ,const std::string & chaine2){ ... }
Ok maintenant il faut corriger deux trois choses, notamment la longueur d'une chaine s'obtient par :
std::size_t taille1=chaine1.size();
Un std::size_t est en réalité un unsigned int.
Pour extraire le morceau de chaîne qui nous intéresse on va utiliser la fonction substr :
https://en.cppreference.com/w/cpp/string/basic_string/substr
unsigned int incluse ( const std::string & chaine1 , const std::string & chaine2 ){ unsigned int compteur=0 , j=0; std::string sous_chaine2; for (unsigned int i=0 ; i<chaine2.size() ; i++) { //en fait on peut même s'arrêter à chaine2.size()-chaine1.size() sous_chaine2=chaine2.substr(i,chaine1.size()); if(chaine1==sous_chaine2){ //les std::string ont un opérateur == bien pratique ;) ++compteur; } } return compteur ; }
Tu noteras que i est défini dans le for ce qui signifie que cette variable n'existera que tant qu'on sera dans le for. Outre le fait que tu gagnes en mémoire, ça évite certaines erreur. Je te conseille donc de fonctionner comme ça par la suite. Ceci dit ça ne marche qu'en C++.
Je n'ai pas compilé le code donc il comporte peut être quelques erreurs, mais je te laisse corriger, c'était juste pour te donner le début.
On peut encore améliorer le programme : la copie de sous_chaine2 fait perdre "beaucoup de temps", donc plutôt que d'utiliser substr, ont pourrait plutôt utiliser la méthode find() :
https://en.cppreference.com/w/cpp/string/basic_string/find
... et à chaque fois qu'une occurence de chaine1 est trouvée dans chaine2, déplacer le début de chaine2... Idéalement c'est comme ça qu'il faudrait faire. Je te laisse expérimenter tout ça ;)
Bonne chance
Est-ce qu'il y a une autre façon plus simple de le faire (avec les notions de base, car je n'ai pas encore tout vu ça en classe...) ?
Merci pour l'aide!
Merci pour l'aide!
umm... Je dois obligatoirement utiliser la fonction dont le prototype est int incluse (char chaine1[] , char chaine2[]); ... Vous l'avez changé pour int incluse (std::string chaine1 ,std::string chaine2){ ... Qu'est-ce que je peux faire maintenant? j Je suis tellement désespérée... =(
Mais merci pour l'aide quand même!
Mais merci pour l'aide quand même!
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
C'est pas grave ça :
Mais bon on peut aussi utiliser strtok :
http://www.manpagez.com/missing.php
Ton séparateur est chaine1 et la recherche se fait dans chaine2.
Bonne chance
int incluse (char _chaine1[] , char _chaine2[]){ const std::string chaine1(_chaine1); const std::string chaine2(_chaine2); //et après tu manipules les strings //... }
Mais bon on peut aussi utiliser strtok :
http://www.manpagez.com/missing.php
Ton séparateur est chaine1 et la recherche se fait dans chaine2.
Bonne chance
Bon on va partir sur strtok().
http://www.manpagez.com/missing.php
- As-tu lu ce que ça faisait ?
- As-tu compris la notion de pointeur ?
Bonne chance
http://www.manpagez.com/missing.php
- As-tu lu ce que ça faisait ?
- As-tu compris la notion de pointeur ?
Bonne chance
J'ai lu ce que strtok fait, mais je ne comprends pas trop. On n'a jamais vu les pointeurs, c'est ça le problème. Comme je te l'ai déjà dit, je suis vraiment débutante en C++. Il n'y a pas un autre moyen de réaliser la fonction sans cette notion?
Ma fonction de départ n'est vraiment pas bonne? On ne pourrait pas la corriger pour qu'elle fonctionne?
Ma fonction de départ n'est vraiment pas bonne? On ne pourrait pas la corriger pour qu'elle fonctionne?
Je viens de refaire une autre fonction avec les notions que j'ai vues en classe. Elle a l'air correcte (pour moi), mais elle affaiche toujours « 0 » (zéro) pour le nombre d'occurences peu importe la séquence de caractères entrée au clavier :
#include <iostream>
#include <string>
using std::cout ;
using std::cin ;
using std::endl ;
int incluse (char chaine1[],char chaine2[]) {
int compteur = 0 ;
int i = 0 ;
while ( i < strlen(chaine2) ) {
if ( strncmp (chaine1 , chaine2 , strlen(chaine1)) == '0') {
compteur++ ;
i = i + strlen(chaine1) ;
}
else {
i = i + strlen(chaine1) ;
}}
return compteur ;
}
main () {
char chaine1[100] ;
char chaine2[100] ;
int compteur ;
cout << "Entrer une chaine de caracteres : \n" ;
cin >> chaine2 ;
cout << "Voici la chaine de caracteres que vous avez entre : \n" << chaine2 << endl ;
cout << "Entrer une sequence de caracteres a rechercher : \n" ;
cin >> chaine1 ;
compteur = incluse (chaine1 , chaine2) ;
cout << "Le nombre d'occurence de la 1re chaine dans la 2e est : \n" << compteur << endl ;
return 0 ;
}
#include <iostream>
#include <string>
using std::cout ;
using std::cin ;
using std::endl ;
int incluse (char chaine1[],char chaine2[]) {
int compteur = 0 ;
int i = 0 ;
while ( i < strlen(chaine2) ) {
if ( strncmp (chaine1 , chaine2 , strlen(chaine1)) == '0') {
compteur++ ;
i = i + strlen(chaine1) ;
}
else {
i = i + strlen(chaine1) ;
}}
return compteur ;
}
main () {
char chaine1[100] ;
char chaine2[100] ;
int compteur ;
cout << "Entrer une chaine de caracteres : \n" ;
cin >> chaine2 ;
cout << "Voici la chaine de caracteres que vous avez entre : \n" << chaine2 << endl ;
cout << "Entrer une sequence de caracteres a rechercher : \n" ;
cin >> chaine1 ;
compteur = incluse (chaine1 , chaine2) ;
cout << "Le nombre d'occurence de la 1re chaine dans la 2e est : \n" << compteur << endl ;
return 0 ;
}
strncmp (chaine1 , chaine2 , strlen(chaine1)) == 0car '0' désigne le code ascii du caractère '0' qui ne vaut a priori pas 0.
Pour strtok, il suffit de suivre un exemple sur google :
https://codes-sources.commentcamarche.net/
L'idée c'est que ton pointeur va aller de séparateurs en séparateurs, en l'occurence la chaine que tu recherches. Il suffit donc ensuite de compter le nombre de séparateurs et c'est dans la poche.
Mais sinon ta solution avec strncmp marchera également c'est juste une manière différente de voir les choses.
Bonne chance
Bon...j'ai corrigé if ( strncmp (chaine1 , chaine2 , strlen(chaine1)) == '0') { pour if ( strncmp (chaine1 , chaine2 , strlen(chaine1)) == 0) { , mais mon programme m'affiche toujours un résultat bizarre.
Par exemple, si ma chaîne2 est : abcdeabcdghabcs
et que ma chaîne1 est : abc
le résultat sera : 5 (au lieu de 3)
et par exemple si ma chaine2 est : bonabcbonabcb
et ma chaine1 est : abc
le résultat sera : 0 (au lieu de 2)
Pourrais-tu me dire directement ce qui ne va pas dans ma fonction (la mienne), car j'ai besoin de remettre ce travail bientôt (dans un jour) et j'aimerais bien avoir la bonne réponse une fois pour toute...svp...
Merci
Par exemple, si ma chaîne2 est : abcdeabcdghabcs
et que ma chaîne1 est : abc
le résultat sera : 5 (au lieu de 3)
et par exemple si ma chaine2 est : bonabcbonabcb
et ma chaine1 est : abc
le résultat sera : 0 (au lieu de 2)
Pourrais-tu me dire directement ce qui ne va pas dans ma fonction (la mienne), car j'ai besoin de remettre ce travail bientôt (dans un jour) et j'aimerais bien avoir la bonne réponse une fois pour toute...svp...
Merci
Préliminaires
1) main retourne un int, donc c'est
2) Soit tu fais un :
soit tu écris std::cout, std::cin... Mais la tes using sont faux.
3) strlen retourne un unsigned int ce qui n'est pas le cas de i :
Note qu'en c++ tu peux déclarer i dans la boucle for ce qui permet de limiter son horizon, ce qui est bien d'un point de vue programmation. Ta boucle peut s'écrire :
Pour éviter ce genre de problème compile par la suite avec les messages de warning. Par exemple sous linux :
4) Je ne comprends pas pourquoi i est incrément de strlen à chaque fois. Par exemple si tu cherches "abc" dans "kabckkk" tu vas louper le abc.
5) Enfin ton bug survient parce que tu ne fais jamais évoluer chaine1 et chaine2 donc à chaque passage de boucle ça refais la même chose. Au lieu d'incrémenter i il faut faire avancer le pointeur chaine2.
Corrigé
Tu noteras l'apparition taille_chaine2, très important puisque la taille de chaine2 va diminuer de 1 à chaque itération.
Exercices
Exercices :
1- résoudre le même problème avec strtok
2- résoudre le même problème avec les std::string
Le premier exo correspond à ce que tu devrais idéalement faire si tu programme en style C (c'est à dire ce que tu as choisi de faire).
Le second exo correspond à ce que tu devrais idéalement faire si tu programmais en style C++
Bonne chance
1) main retourne un int, donc c'est
: int main(){ ... return 0; }
2) Soit tu fais un :
using namespace std;
soit tu écris std::cout, std::cin... Mais la tes using sont faux.
3) strlen retourne un unsigned int ce qui n'est pas le cas de i :
unsigned int i = 0 ; while ( i < strlen(chaine2) ; i += strlen(chaine1) )
Note qu'en c++ tu peux déclarer i dans la boucle for ce qui permet de limiter son horizon, ce qui est bien d'un point de vue programmation. Ta boucle peut s'écrire :
for(unsigned int i=0;i<strlen(chaine2){ if(strncmp (chaine1 , chaine2 , strlen(chaine1)) == 0) ++compteur }
Pour éviter ce genre de problème compile par la suite avec les messages de warning. Par exemple sous linux :
g++ -W -Wall plop.cpp
4) Je ne comprends pas pourquoi i est incrément de strlen à chaque fois. Par exemple si tu cherches "abc" dans "kabckkk" tu vas louper le abc.
5) Enfin ton bug survient parce que tu ne fais jamais évoluer chaine1 et chaine2 donc à chaque passage de boucle ça refais la même chose. Au lieu d'incrémenter i il faut faire avancer le pointeur chaine2.
Corrigé
int incluse (char chaine1[],char chaine2[]) { int compteur = 0 ; unsigned int taille_chaine2 = strlen(chaine2); for(unsigned int i=0 ; i < taille_chaine2 ;++chaine2,++i ) { std::cout<<"compteur="<<compteur<<" i="<<i<<" chaine2="<<chaine2<<std::endl; if ( strncmp (chaine1 , chaine2 , strlen(chaine1)) == 0) { compteur++ ; } } return compteur ; }
Tu noteras l'apparition taille_chaine2, très important puisque la taille de chaine2 va diminuer de 1 à chaque itération.
Exercices
Exercices :
1- résoudre le même problème avec strtok
2- résoudre le même problème avec les std::string
Le premier exo correspond à ce que tu devrais idéalement faire si tu programme en style C (c'est à dire ce que tu as choisi de faire).
Le second exo correspond à ce que tu devrais idéalement faire si tu programmais en style C++
Bonne chance