AideZ moi en c++ ?
mina
-
strato-boy Messages postés 769 Date d'inscription Statut Membre Dernière intervention -
strato-boy Messages postés 769 Date d'inscription Statut Membre Dernière intervention -
Bonjour,j'ai trouve un grand probleme :je Sui une debutante en c++ ,meS programmeS marchent bien mais il Suffit de lire une information de l'eXterieure(Scanf ) pour que la fenetre d'eXecution cesse de fonctionner pourquoi et comment je peuX eviter ça? merci
8 réponses
Je pense que tu peux mais c'est maladroit...
Bien sûr si tu débutes tu ne t'en rends pas encore compte, mais l'intérêt de cin/cout dépasse largement celui de scanf/printf en C++ (en particulier lorsque tu feras tes propres opérateurs)
Exemple d'utilisation :
Bien sûr si tu débutes tu ne t'en rends pas encore compte, mais l'intérêt de cin/cout dépasse largement celui de scanf/printf en C++ (en particulier lorsque tu feras tes propres opérateurs)
Exemple d'utilisation :
#include <iostream> int main() { int n; std::cout << "Entrez un nombre : "; std::cin >> n; std::cout << "Le nombre est " << n << std::endl; system("PAUSE"); return EXIT_SUCCESS; }on peut afficher (avec std::cout <<) ou lire (avec std::cin >>) n'importe quel type primitif
ouais et il faut lui dir que pour eviter de repeter std:: il faut ajouter using namespace std; apres les bibliotheques
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
Tu peux tout à fait utiliser scanf en C++ mais il faut plutôt inclure <cstdio>. En C ce serait <stdio.h>. De la même façon, la plupart des headers C (<assert.h>, <time.h>,...) ont une version pour le C++ (<cassert>, <ctime>...).
Bonne chance
Bonne chance
scanf c'est en c et il faut que tu utilises la bib #include <stdio.h> et scanf ne marche pas en C++. Si tu travailles avec scanf la ton programme c'est du C et pas du C++. Je pense ça parce que je suis débutante en programmation et bonne chance a tous
Non scanf existe aussi en C++. En tant que fonction provenant du langage C il faut simplement inclure <cstdio> au lieu de <stdio.h>. Ces fichiers ne sont pas des librairies mais des headers (et printf est implémentée dans la librairie standard C communément appelée libc).
De plus scanf (et autres fscanf, sscanf...) ne répondent pas au même besoin qu'un opérateur comme >> en C++. En particulier un fscanf (ou un scanf, sscanf...) permet de contrôler qu'une chaîne vérifie un certain motif.
Ceci dit, pour vérifier le format d'une chaîne on peut également utiliser la librairie PCRE. En tout cas "scanf" n'est absolument pas une fonction réservée au C et peut tout à fait être utilisée dans du C++.
De plus scanf (et autres fscanf, sscanf...) ne répondent pas au même besoin qu'un opérateur comme >> en C++. En particulier un fscanf (ou un scanf, sscanf...) permet de contrôler qu'une chaîne vérifie un certain motif.
Ceci dit, pour vérifier le format d'une chaîne on peut également utiliser la librairie PCRE. En tout cas "scanf" n'est absolument pas une fonction réservée au C et peut tout à fait être utilisée dans du C++.
Tiens puisqu'on en parle, comment vérifier un motif avec sscanf quand ce motif doit contenir plusieurs string ?
Mon motif est le suivant "%d|%u|%s|%s|"
Je suis sûr que la première chaîne de caractères ne contient pas de '|' (c'est un nom de fichier Windows)
Mais quand j'utilise sscanf_s, la première chaîne de caractères récupère tout jusqu'à la fin sans s'arrêter au '|'
Alors j'ai contourné le problème "à la main" avec une boucle for très scolaire...
Mais puisqu'on en est à expliquer scanf, si on pouvait m'aider sur ce point. merci !
Mon motif est le suivant "%d|%u|%s|%s|"
Je suis sûr que la première chaîne de caractères ne contient pas de '|' (c'est un nom de fichier Windows)
Mais quand j'utilise sscanf_s, la première chaîne de caractères récupère tout jusqu'à la fin sans s'arrêter au '|'
Alors j'ai contourné le problème "à la main" avec une boucle for très scolaire...
Mais puisqu'on en est à expliquer scanf, si on pouvait m'aider sur ce point. merci !
#include <iostream> #include <string> using namespace std; #define BUF_SIZE 100 typedef struct { enum { X,Y,Z } mode; size_t taille; string fichier; string nom; } maStruct; string structToString(maStruct m) { char buffer[BUF_SIZE]; int i=0; i+=sprintf_s(buffer+i,BUF_SIZE-i,"%d|",m.mode); i+=sprintf_s(buffer+i,BUF_SIZE-i,"%u|",m.taille); i+=sprintf_s(buffer+i,BUF_SIZE-i,"%s|",m.fichier.c_str()); i+=sprintf_s(buffer+i,BUF_SIZE-i,"%s|",m.nom.c_str()); string s(buffer,i); return s; } maStruct stringToStruct(string s) // "1|234|ab.c|def|" { maStruct m; char buf1[BUF_SIZE], buf2[BUF_SIZE]; sscanf_s(s.c_str(),"%d|%u|%s|%s|", &m.mode, // Y &m.taille, // 234 buf1,sizeof(buf1), // "ab.c|def" buf2,sizeof(buf2)); // "ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ...ab.c|def|" m.fichier.assign(buf1); m.nom.assign(buf2); return m; } int main(int argc, char* argv[]) { maStruct m=stringToStruct("1|234|ab.c|def|"); string s=structToString(m); cout << s << endl; return 0; }
En ce qui me concerne voici comment je ferais :
En C++ avec la librairie PCRE
1) lire la ligne courante avec std::getline et la stocker dans une std::string (appelons la "line").
http://www.cplusplus.com/reference/string/string/getline/
2) utiliser la librairie PCRE en vue d'extraire chaque morceau de line via une expression régulière. L'expression régulière permet de vérifier le format de la ligne et d'extraire chaque morceau. La plupart des expressions régulières "classiques" (adresse IP, valeur numérique etc...) peuvent se retrouver sur le Net.
C'est la méthode la plus élégante à mon avis, très efficace. La seule difficulté consiste à écrire l'expression régulière.
Autre méthode : en C++ (dans la douleur)
Tu ne veux pas / peux pas / sais pas installer la librairie pcre ou tu ne sais pas utiliser une expression régulière.
1) tu lis la ligne courante avec std::getline
2) tu fais une boucle sur cette chaîne qui maintient ces variables :
- la position de début de champ
- la position de fin de champ
- le nombre de caractères | rencontrés
Dès que tu rencontres un caractère | tu mets à jour ces variables. Avec la méthode substring (https://community.hpe.com/t5/custom/page/page-id/HPPSocialUserSignonPage?redirectreason=permissiondenied&referer=https%3A%2F%2Fcommunity.hpe.com%2Ft5%2FServers-Systems-The-Right%2FSGI-com-Tech-Archive-Resources-now-retired%2Fba-p%2F6992583 tu peux alors extraire le champ courant et le manipuler sous forme de const char * avec la méthode c_str(). Il ne reste avec un sscanf qu'à contrôler la nature de cette chaîne. Si celle-ci est invalide, la ligne est invalide et on peut interrompre la boucle pour passer à la ligne suivante.
Le problème de cette approche et que tu as de forte chance de te mélanger les pinceaux en codant. Et si le format de fichier évolue, le code est difficilement réutilisable contrairement à la première approche.
Dernière méthode : comme en C
Évidemment l'idéal serait d'utiliser directement des char * et des pointeurs comme en C, ce serait le plus efficace que d'utiliser des index.
Le problème c'est qu'on n'est pas forcément en mesure de borner le buffer (la chaîne) qui va stocker la ligne courante, donc il est difficile de l'allouer de manière statique (char buffer[512]).
Une ligne trop longue fera planter le programme. Soit dit en passant, c'est ce que tu fais avec BUF_SIZE.
Il serait contre-productif de l'allouer dynamiquement (malloc, realloc) car ce sera coûteux en termes de performances. Donc au final c'est s'ennuyer pour ne rien gagner.
Ceci dit c'est ce que fait la fonction getline du C. C'est comme ça qu'on s'en sort à peu près si on est pas en C et qu'on ne peut pas borner la longueur d'une ligne.
https://linux.die.net/man/3/getline
Si l'on peut dimensionner statiquement le buffer, c'est plus performant que d'utiliser des std::string mais à mon avis le gain est négligeable.
Ensuite on extrait les champs intéressants comme indiqué dans la deuxième méthode.
Note : quand je parle de performances si ton fichier est petit (quelques dizaines de lignes) ce sera imperceptible. Il faut vraiment manipuler de gros fichiers (plusieurs milliers de ligne) pour commencer à ressentir une différence.
Bonne chance
En C++ avec la librairie PCRE
1) lire la ligne courante avec std::getline et la stocker dans une std::string (appelons la "line").
http://www.cplusplus.com/reference/string/string/getline/
2) utiliser la librairie PCRE en vue d'extraire chaque morceau de line via une expression régulière. L'expression régulière permet de vérifier le format de la ligne et d'extraire chaque morceau. La plupart des expressions régulières "classiques" (adresse IP, valeur numérique etc...) peuvent se retrouver sur le Net.
C'est la méthode la plus élégante à mon avis, très efficace. La seule difficulté consiste à écrire l'expression régulière.
Autre méthode : en C++ (dans la douleur)
Tu ne veux pas / peux pas / sais pas installer la librairie pcre ou tu ne sais pas utiliser une expression régulière.
1) tu lis la ligne courante avec std::getline
2) tu fais une boucle sur cette chaîne qui maintient ces variables :
- la position de début de champ
- la position de fin de champ
- le nombre de caractères | rencontrés
Dès que tu rencontres un caractère | tu mets à jour ces variables. Avec la méthode substring (https://community.hpe.com/t5/custom/page/page-id/HPPSocialUserSignonPage?redirectreason=permissiondenied&referer=https%3A%2F%2Fcommunity.hpe.com%2Ft5%2FServers-Systems-The-Right%2FSGI-com-Tech-Archive-Resources-now-retired%2Fba-p%2F6992583 tu peux alors extraire le champ courant et le manipuler sous forme de const char * avec la méthode c_str(). Il ne reste avec un sscanf qu'à contrôler la nature de cette chaîne. Si celle-ci est invalide, la ligne est invalide et on peut interrompre la boucle pour passer à la ligne suivante.
Le problème de cette approche et que tu as de forte chance de te mélanger les pinceaux en codant. Et si le format de fichier évolue, le code est difficilement réutilisable contrairement à la première approche.
Dernière méthode : comme en C
Évidemment l'idéal serait d'utiliser directement des char * et des pointeurs comme en C, ce serait le plus efficace que d'utiliser des index.
Le problème c'est qu'on n'est pas forcément en mesure de borner le buffer (la chaîne) qui va stocker la ligne courante, donc il est difficile de l'allouer de manière statique (char buffer[512]).
Une ligne trop longue fera planter le programme. Soit dit en passant, c'est ce que tu fais avec BUF_SIZE.
Il serait contre-productif de l'allouer dynamiquement (malloc, realloc) car ce sera coûteux en termes de performances. Donc au final c'est s'ennuyer pour ne rien gagner.
Ceci dit c'est ce que fait la fonction getline du C. C'est comme ça qu'on s'en sort à peu près si on est pas en C et qu'on ne peut pas borner la longueur d'une ligne.
https://linux.die.net/man/3/getline
Si l'on peut dimensionner statiquement le buffer, c'est plus performant que d'utiliser des std::string mais à mon avis le gain est négligeable.
Ensuite on extrait les champs intéressants comme indiqué dans la deuxième méthode.
Note : quand je parle de performances si ton fichier est petit (quelques dizaines de lignes) ce sera imperceptible. Il faut vraiment manipuler de gros fichiers (plusieurs milliers de ligne) pour commencer à ressentir une différence.
Bonne chance
Merci de ta réponse, j'ai récupéré tout ce que je pouvais de tes méthodes.
Ta deuxième méthode est à peu près celle que j'avais faite pour contourner le problème.
Bref, j'ai réussi avec des "expressions régulières", mais sans utiliser PCRE.
Et en améliorant les performances avec c_str(), ça me donne :
Merci encore
Ta deuxième méthode est à peu près celle que j'avais faite pour contourner le problème.
Bref, j'ai réussi avec des "expressions régulières", mais sans utiliser PCRE.
Et en améliorant les performances avec c_str(), ça me donne :
maStruct stringToStruct2(string s) // "1|234|ab.c|def|" { maStruct m; sscanf_s(s.c_str(),"%d|%u|%[^|]|%[^|]|", &m.mode, // Y &m.taille, // 234 m.fichier.c_str(),s.length(), // "ab.c" m.nom.c_str(),s.length()); // "def" return m; }
Merci encore