AideZ moi en c++ ?

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

KX Messages postés 16761 Date d'inscription   Statut Modérateur Dernière intervention   3 020
 
En C++ on n'utilise pas scanf mais std::cin (avec #include <iosteam>)
0
..mina Messages postés 3 Date d'inscription   Statut Membre Dernière intervention  
 
c pa poSSible avec #include <stdio.h> et scanf ?
0
KX Messages postés 16761 Date d'inscription   Statut Modérateur Dernière intervention   3 020
 
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 :
#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
0
MHV-SEC Messages postés 116 Date d'inscription   Statut Membre Dernière intervention   11
 
ouais et il faut lui dir que pour eviter de repeter std:: il faut ajouter using namespace std; apres les bibliotheques
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   7 884
 
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
0
mina
 
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
0
mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   7 884
 
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++.
0
KX Messages postés 16761 Date d'inscription   Statut Modérateur Dernière intervention   3 020
 
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 !

#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;
}
0
mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   7 884
 
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
0
KX Messages postés 16761 Date d'inscription   Statut Modérateur Dernière intervention   3 020
 
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 :

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
0
strato-boy Messages postés 769 Date d'inscription   Statut Membre Dernière intervention   101
 
pourrait-tu donner un exemple de tes programme (court si possible ) pour l'examiner, et tu utilise quoi comme logiciel pour coder ?

[edit] : shit ! foutu rafraichissement de page ! j'arrive après la guerre ...
les 3 pire catastrophe du siècles :
Hiroshima 45 / Tchernobyl 86 / Windows '95
0