Bonjour à tous,
J'ai un petit souci.
J'aimerais traduire ce programme C++ en C.
Il permet de récupérer dans un fichier une chaîne de caractères en allouant dynamiquement un pointeur sur la chaîne et affiche cette chaîne.
#include <algorithm>
#include <iostream>
#include <vector>
#include <fstream>
using Buffer = std::vector< char >;
void display( Buffer::const_iterator begin, Buffer::const_iterator end )
{
std::for_each( begin, end, []( char c )
{
std::cout << static_cast< int >( c ) << " ";
} );
}
int main( int argc, char * argv[] )
{
//on prend le fichier en entrée du programme, donc on veut au moins 2 arguments.
if ( argc < 2 )
{
std::cerr << "Usage: coin myfile" << std::endl;
return EXIT_FAILURE;
}
// Le fichier, ouvert en lecture
std::fstream file( argv[1], std::ios::in );
if ( file.is_open() )
{
// Mon buffer
Buffer buffer( 20 );
file.read( buffer.data(), 1 );
if ( !file.fail() )
{
display( buffer.begin(), buffer.begin() + 1 );
}
// Tant qu'on n'a pas fini le fichier, on va le lire
while ( !file.eof() && !file.bad() && !file.fail() && file.rdbuf()->in_avail() )
{
// Je lis le fichier, en ne lisant que ce que mon buffer peut contenir
// Et je récupère le nombre d'octets lus pour plus tard
auto read = file.readsome( buffer.data(), buffer.size() );
//je ne vais afficher que ce que j'ai lu
if ( read && !file.fail() )
{
display( buffer.begin(), buffer.begin() + int( read ) );
}
}
file.close();
std::cout << std::endl;
}
else
{
std::cerr << "Couldn't open the file" << std::endl;
}
return 0;
}
Merci d'avance !
# Bonjour
Posté par Marotte ⛧ . Évalué à 4.
Il faudrait déjà que tu postes le programme en C que tu as commencé à écrire et on pourra peut-être te dire ce qui ne va pas… ou au moins que tu précises sur quel point tu penses avoir des difficultés…
Pourquoi veux-tu traduire ce programme en C ?
[^] # Re: Bonjour
Posté par roger91 . Évalué à 2. Dernière modification le 30 décembre 2015 à 08:32.
Bonjour Marotte,
Mon problème se situe précisément au niveau de l'allocation dynamique pour le buffer que je n'arrive pas à traduire en C. Je cherche à le faire pour m'exercer. C'est l'exo qui me demande de l'écrire dans les deux langages. Ce que j'ai fait:
Merci !
[^] # Re: Bonjour
Posté par freem . Évalué à 3.
1ère remarque, la commande
man
est ton amie (sur linux, pas sur windows ou elle n'existe pas). C'est facile, je sais, mais à l'école on m'a toujours dis qu'il fallait dire le moins pertinent en premier :)2: avec man malloc, tu verras que malloc peut échouer. Du coup, de même que tu as vérifié le retour de
fopen
il serait de bon ton de vérifier le retour demalloc
.3: ne pas utiliser de valeurs magiques. Ton fameux
20*
qui apparaît à plusieurs reprises, mets-le plutôt dans une constante, comme ça par exemple:const int MAX_READ=20;
. Ça te fera gagner du temps quand tu devras te relire, et quand tu t'apercevras que cette valeur est trop faible: un nom qui cause, et un remplacement unique dans l'ensemble de tes fichiers source.4: attention au style de codage. Si tu utilises une convention, utilises-la jusqu'au bout, ça t'éviteras pas mal de comportement non souhaités, aussi appelés: bugs. Par exemple, cette ligne:
while (pointeur[k]) printf("%d\t", (int) pointeur[k++]);
serait sûrement plus claire si coupée. D'ailleurs, un œil exercé pourrait ainsi repérer le copier/coller, et donc envoyer le code dans une fonction dédiée (collage tout à la fin, l'autre boucle while…).5: en tant que débutant, évites de combiner les opérateurs d'incrémentation et décrémentation avec d'autres. Selon qu'il s'agisse de post/pré - in/dé crémentation, les résultats peuvent être traîtres.
6: encore le style de codage: tes indentations, soigne-les. L'indentation est ton amie, si tu la trahis, elle te rendras la même. Je sais, je me répète un peux rapport au point 4, mais il est possible que tu n'aies pas remarqué que tu utilises un pointeur déjà libéré à cause de ça…
[^] # Re: Bonjour
Posté par benja . Évalué à 2.
J'ajouterais aussi que l'utilisation systématique des options de compilations -Wall et autres -pedantic permet de débusquer pas mal de mauvaises utilisations et éviter ainsi de prendre de mauvaises habitudes; d'expérience, clang tend (tendait?) à être plus prolifique sur ce point que gcc.
Et tant qu'à faire, apprendre à utiliser des outils comme gdb, valgrind/memcheck et les analyseurs statiques, dans l'ordre inverse de difficulté mais aussi d'utilité je trouve ;-).
[^] # Re: Bonjour
Posté par benja . Évalué à 2.
[^] # Re: Bonjour
Posté par benja . Évalué à 1.
ps: tu peux utiliser sizeof(pointeur*);
[^] # Re: Bonjour
Posté par roger91 . Évalué à 1.
Merci benja pour ta réponse.
Je voulais juste généraliser mon programme au cas ou la taille de la chaine de caractères n'était pas connu à l'avance car là j'ai donné une taille fixe qui est 20. Le code en lui meme marche, il n'y a pas d'erreurs.
[^] # Re: Bonjour
Posté par benja . Évalué à 1. Dernière modification le 30 décembre 2015 à 11:28.
Oui, et c'est justement une bonne idée. Je pointe juste une erreur dans la mise en oeuvre qui fait que actuellement tu autorises un dépassement de 3 à 7 fois (sur x86 32 ou 64 bits) la taille du buffer au lieu de t'en prémunir…
Là dans ton appel à fgets c'est comme si tu dis "je t'autorise à écrire dans un tampon qui a de la place pour 20 pointeurs", alors qu'en réalité ton tableau n'a de la place que pour 20 charactères.
[^] # Re: Bonjour
Posté par benja . Évalué à 1.
Et tu auras bien sûr corrigé que c'est
sizeof(*ptr_type)
qui donne la taille de l'objet pointé à la place desizeof(type*)
qui lui donne justement la taille d'un pointeur (qui aura toujours la même taille, quelle que soit le type de l'objet pointé, soit la taille d'une adresse mémoire).[^] # Re: Bonjour
Posté par roger91 . Évalué à 1.
Merci benja pour ta réponse.
C'est cela l'objet de ma demande d'aide.
Comment devrais je le modifier dans ce cas mon programme pour remédier à ce problème ?
[^] # Re: Bonjour
Posté par benja . Évalué à 2. Dernière modification le 30 décembre 2015 à 11:57.
Tu dois utiliser la même taille des deux côté. Quelque chose comme:
Ou une n'importe quelle autre combinaison tant que fgets reçoit la même valeur que malloc a reçu. Je préfère la première forme car à chaque utilisation on sait exactement de quoi il s'agit, dans la deuxième forme il reste l'ambiguité : est-ce que buffer_size est exprimé en taille d'octes (= char) ou en nombre d'objet avec le risque de te tromper comme tu l'as justement fait.
N'oublies pas aussi, comme on te l'a fait remarquer, de vérifier le retour de malloc, i.e. if (0 == pointeur) { return …/exit(1)} par example, et de fgets ! Extrait de la page "man fgets" : fgets() returns s on success, and NULL on error or when end of file occurs while no characters have been read (note: les pages man sont disponibles en traduction française aussi).
[^] # Re: Bonjour
Posté par roger91 . Évalué à 1.
Ok merci benja.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.