-1
votes

fscanf ()! = eof comme condition de sortie de la boucle sort au mauvais moment

Je prends l'entrée de Ce fichier , que je sais contient une série d'éléments de type: xxx

mais lorsque je prends mon entrée avec une boucle, le programme pense qu'il atteint eof juste après la première structure, même si J'ai découvert qu'il y a 9 de ces éléments, puis un bouquet de poubelles. Donc, dans le pire des cas, il devrait imprimer une bande de déchets après les 9 pistes, mais ne lit que le premier, puis le pense avoir frappé eof .

au début, j'avais tandis que (! Feof (fp)) , mais j'ai lu c'est vraiment mauvais code, j'ai donc essayé le retour du FSCANF comme tout le monde semble suggérer, mais cela ne fonctionne toujours pas. xxx

sortie est: xxx

pendant qu'il devrait réellement imprimer 8 autres pistes de ce même format.


7 commentaires

FSCANF peut avoir d'autres modes de panne en plus de eof !


De plus, le fichier que vous lisez est un fichier binaire et fscanf n'a aucun sens uniquement sur le texte.


Misté: Vérifiez le résultat de FSCANF contre ce que vous veux Ce n'est pas ce que vous ne ne veux pas que ce soit. C'est-à-dire le nombre d'éléments numérisés.


Veuillez ajouter un exemple de fichier texte à la question elle-même: le lien n'est pas bon - Oh! Ce n'est pas du tout un fichier texte.


@Anttihaapala Quelle autre fonction recommandez-vous? fgetc () ? @Meathervane je vais, merci pour l'entrée. Néanmoins, je ne suis pas sûr de savoir pourquoi ça ne marche pas


@WeatherVane commence hexdump avec 0000000 7246 6e61 206b 615a 0000 0000 0061 7070 0000 0000 0000 0000010 0000 0000 0000 0000 0000


Le format de ce fichier est-il documenté n'importe où?


4 Réponses :


0
votes

Puisque vous n'avez pas posé une question spécifique, je vais essayer de vous mettre dans la bonne direction.

Le fichier que vous avez identifié est un fichier binaire contenant des enregistrements de struct piste . Vous ne pouvez donc pas le lire avec FSCANF () . Vous pouvez utiliser Fread () comme alternative standard; Veuillez lire sa documentation pour savoir comment l'utiliser et ce qu'il revient. Pensez à l'endansion si le fichier est écrit sur un ordinateur et lisez sur un autre ordinateur.

L'autre problème évident a été mentionné dans les commentaires: la famille de scanf () La fonction renvoie le nombre de champs numérisés avec succès. S'il y a une erreur, il retournera une valeur int moins que prévu.


0 commentaires

0
votes

Au début, vous essayez apparemment de lire des données binaires, voir Busybee 'S Réponse Pour ce numéro (FSCANF n'est pas applicable sur les données binaires!).

Deuxièmement (maintenant supposons que les données auraient été stockées dans un texte em> fichier), FSCANF code> A> ne renvoie pas l'état du flux de fichiers, mais le nombre d'arguments numérisés avec succès, vous devez donc vérifier l'égalité sur le nombre de paramètres de format, i. e. 5 code> dans votre cas. p>

Si vous souhaitez également vérifier pour avoir atteint la fin du fichier, vous pouvez utiliser feof code> avec le fichier code> pointeur comme argument. Sachez cependant que la lecture peut échouer pour Autres raisons , aussi. Votre code peut alors ressembler à ceci à la place: P>

while(fscanf(...) == 5) { /* ... */ }
if(feof(fp))
{
    // you read entire file
}
else
{
    // something went wrong
}


0 commentaires

4
votes

Vous ne pouvez pas utiliser fscanf () pour lire un fichier binaire, et votre est un binaire.

connaissant le format binaire du fichier, vous pouvez reproduire la structure et la copier de Fichier à l'aide d'un Fread () .

Analizying Le fichier Nous pouvons voir que la structure n'est pas rembourrée, alors à l'aide d'un attribut d'emballage, nous pouvons forcer le compilateur à faire la même chose.

Le code sera le suivant: xxx

edit : Notez l'utilisation du type int32_t < / code> Pour forcer l'utilisation de 32bits (4Bans) entiers. Ceci est absolument obligatoire de garder la configuration de la structure sur les systèmes où le type standard int est <> 32bits .

Observant la disposition du fichier que nous Peut trouver un motif répétitif qui ressemble à la structure fournie: xxx

l'observant que nous voyons que les champs ne sont entrés pas par aucun rembourrage (au moins en considérant les tailles standard pour int32_t .

D'autre part, la structure sans attribut d'emballage laissera la liberté du compilateur pour éventuellement ajouter un remplissage dépendant de la mise en œuvre, éventuellement conduisant à la défaillance de la mémoire si la disposition de la mémoire est incompatible. La mise en page de fichier.

Une autre possibilité, de contourner de tels problèmes consiste à Serialize l'entrée, dans ce cas, vous allez lire chaque champ à l'aide de sa longueur. < P> Juste un autre mot sur l'utilisation de Taille_t Freead (VOID * PTR, Taille_T Taille, Taille_T Compte, Fichier * Stream) (Voir plus d'informations ici http://www.cplusplus.com/reference/cstdio/fread/ ). Réglage Nombre = 1 et Taille = Tailleof (piste) signifie que Fread () doit lire au moins Taille < / code> octets à l'heure par chaque élément et un élément seulement . Si le fichier atteint la fin avant que ce nombre d'octets puisse être lu, la fonction renvoie 0 éléments, cela représente de faux. Si un élément complet peut être lu la fonction renvoie 1 élément lu pour le vrai.

dernier, soyez conscient de l'endianesse. Dans votre fichier, il s'agit d'un format petit-Endian, si votre machine est BIG-Endian Swap Bytees de int membres de la structure.


11 commentaires

Je suis désolé, je ne suis pas vraiment sûr de ce que vous avez fait là-bas. Comment savez-vous que la structure n'est pas rembourrée? L'ouverture du fichier affiche un tas de \ 00 (qu'est-ce que c'est?) Et Hexdump -C imprime les noms et artistes, puis un tas de points, ce qui me fait penser qu'il est rembourré, car les données ne sont pas contiguës. Cela vous dérangerait-il de clarifier?


Cher pirate Regardant votre structure Nous comptons 2 membres de chaîne, chaque 50 octets large, puis 3 int 32 bits ou 4 octets chacun. L'ajout simplement que vous avez 50 * 2 + 4 * 3 = 112 octets chaque enregistrement. Il n'y a pas de rembourrage car il n'y a pas d'espaces inutilisés entre les champs. Tous les 112 octets dans le fichier toute la structure redémarre. Vous pouvez utiliser un éditeur Hex pour vérifier le fichier à l'intérieur. Les zéros que vous voyez sont des pavages, mais de l'élément de structure unique, pas de la structure elle-même . De plus, dans les 2 derniers enregistrements, le membre est ...


rempli de déchets. Mais vous n'avez pas à vous soucier car les données intéressantes s'arrêtent au premier octet zéro (fin pour les chaînes C). D'autre part, peut même arriver que les 3 champs numériques sont plus courts de 32 bits et la structure rembourrée sur une limite de 32 bits, mais même dans ce cas, le système fonctionne toujours que si le rembourrage ne contient pas de données différentes de zéros (dans ce cas, vous pouvez masquez-les). Quoi qu'il en soit, vous DOIT utiliser une structure emballée car tout autre type n'a pas pu respecter la structure de la structure dans le fichier (comment le rembourrage est dépendant du compilateur). Donc, pour un bon ingénierie inverse, vous devez ...


Observez soigneusement, essayez d'étudier un peu plus de langage C. Buona Fortuna ;-)


Vous n'avez pas besoin de rembourrage, la structure est (croire ou non) naturellement emballée. Le plus notamment int32_t est nécessairement aligné au plus 4 octets.


@Anttihaapala merci. Il est vrai que les 4Bytes sont un alignement naturel sur presque tous les systèmes, mais peuvent arriver que sur un système très rare (intégré ou DSP), cela ne peut pas s'adapter. Donc, juste au cas où ... je préférerais forcer l'emballage ;-)


@Frankie_C Eh bien, s'il y a une DSP intégrée avec une taille de caractère aléatoire, sur laquelle vous essayez de lire tous les deux caractères de ce fichier et < code> int32_t s vous avez biiiiiiiiiiiiiiiiiiiig problème .


En tout cas, il suit nécessairement que, à moins que le compilateur ajout de un remplissage inutile puis une structure que ces membres sont toujours naturellement alignées;) y compris votre chari_bit 16 DSPS


@Anttihaapala oui tu as raison :-d avec un DSP pur sera très difficile :-D


C'est à dire. Ce que je veux dire, c'est que si les caractères comme a sont censés être un char , comment se fait-il que cela puisse lire le int32_t if < Code> Char_bit est dit 16.


@Anttihaapala j'ai compris. Je suis d'accord, le code ne peut pas s'appliquer sur une machine que char n'est pas 8 bits (selon le symbole char_bit fourni pour la norme C). Cela devrait fonctionner pour d'autres (ARM Cortex avec DSP devrait être conforme).



1
votes

La chose intéressante ici n'est pas tellement que le programme n'émet qu'un seul disque: cela se produit car il n'y a pas de nouvelles lignes dans le fichier (binaire), une tentative est nécessaire pour consommer tout le contenu du fichier pour gérer le premier % [^ \ n] code> directive du format, la première fois FSCANF code> est appelé.

Non, la chose intéressante est que l'enregistrement qu'il émet semble sensible malgré la lecture malgré la lecture aller horriblement faux. C'est-à-dire que, car il n'y a pas de nouvelle ligne dans les 50 premiers caractères, la numérisation du premier champ dépassait les limites de la chanson chanson [0] .artiste code>, produisant un comportement non défini. P>

se livrer à Un peu de spéculation sur la manifestation de cette UB, le résultat semble avoir été comme si le programme vient d'écraser tous les octets du fichier dans la représentation de la maquette code> (qui est suffisamment longue pour accueillir Ils), et que la structure de la structure code> code> correspond à correspondre au format binaire du fichier (qui n'est pas si surprenant). En conséquence, tous les champs de la première piste semblent avoir été correctement remplis. P>

En outre, les détails de la structure de la piste sont tels qu'il est peu susceptible d'être aménagé avec une fuite (ou interne) Rembourrage, nous pourrions même spéculer que l'impression d'autres pistes, en dehors de la boucle, pourrait également entraîner des données attendues. P>

assez intéressant, sur un système qui a la même endansion et les mêmes conventions de structure La mise en page comme celle avec laquelle le fichier a été écrit et supposant que la structure soit aménagée sans aucun rembourrage, le mode de lecture correct le plus simple de lire la caractérisation possible ci-dessus de FSCANF code> SUB: p> xxx pré>

lit simplement le fichier entier (jusqu'à n code> pistes) directement dans la représentation de la matrice. Vous pouvez ensuite boucler simplement pour imprimer les résultats: P>

for (int i = 0; i < num_songs; i++) {
    printf("Artist: %s\nTitle: %s\nNum: %d\nLength: %d:%d\n\n",
            song[i].artist, song[i].title, song[i].num, song[i].minutes,
            song[i].seconds);
}


5 commentaires

Il n'est pas nécessaire de mettre de la chanson entre parenthèses. Taille de est comme un opérateur unaire déterminant la taille de l'objet utilisé sur. Parce que nous mettons souvent un casting là-bas, il ressemble à une fonction, par exemple Tailleof (int) .


Oui, @thebusybee, Tailleof est un opérateur. Les parenthèses que j'ai utilisées dans ce cas ne sont pas obligatoires. Mais ce n'est pas l'un des problèmes que je voulais entrer avec l'OP, qui est presque certainement utilisé pour voir les parenthèses.


C'est vrai, c'est juste que j'aimerais voir un bon code dans des exemples.


Bien que les parenthèses puissent être omises omis, @Thebusybee, ils sont tellement idiomatiques que je rejette complètement la proposition que cela rendrait le code meilleur de quelque manière que ce soit qui compte pour moi.


Soupir ... ;-) Pas d'offense.