أسهل طريقة لقراءة هذا الخط من النص في بنية؟

StackOverflow https://stackoverflow.com/questions/3878327

  •  28-09-2019
  •  | 
  •  

سؤال

لدي ملف نصي يحتوي على بيانات في النموذج:

Lee AUS 2 103 2 62 TRUE
Check AUS 4 48 0 23 FALSE
Mills AUS 8 236 0 69 FALSE

أحتاج إلى كل سطر في بنية مثل ، ومع ذلك أود تجنب استخدام صفائف الطول الثابتة (مشكلة FGTS بقدر ما أستطيع أن أقول):

struct Data
{
    char *sname;
    char *country;
    int *a;
    int *b;
    int *c;
    int *d;
    char *hsisno;
};

أنا جديد جدًا على C. هل يجب أن أستخدم FSCANF ، أو fgets؟

هل كانت مفيدة؟

المحلول

fscanf تعني "مسح الملفات منسقة"وبيانات المستخدم تدور حولها غير مهتم كما يمكنك الحصول عليها.

يجب ألا تستخدم عارية "%s" تنسيق السلاسل على البيانات حيث لا يكون لديك سيطرة مطلقة على ما يمكن قراءته.

أفضل حل هو الاستخدام fgets لقراءة خط لأن هذا يتيح لك منع تدفق المخزن المؤقت.

بعد ذلك ، بمجرد معرفة حجم خطك ، هذا هو الحد الأقصى لحجم كل سلسلة ستطلبها. يستخدم sscanf إلى محتوى قلبك للحصول على الحقول الفعلية.

شيء آخر. من المحتمل أن يكون هناك مضيعة بعض الشيء int* أنواع الأعداد الصحيحة ، نظرًا لأنك تعلم أن لديهم حجمًا أقصى محدد بالفعل. سأستخدم البديل غير المؤشر ، شيء مثل:

struct Data {
    char *sname; char *country;
    int a; int b; int c; int d;
    char *hsisno;
};

على سبيل المثال ، إليك بعض التعليمات البرمجية الآمنة:

#include <stdio.h>
#include <string.h>

// Here's all the stuff for a linked list of your nodes.

typedef struct sData {
    char *sname; char *country; char *hsisno;
    int a; int b; int c; int d;
    struct sData *next;
} Data;
Data *first = NULL; Data *last = NULL;

#define MAXSZ 100
int main (void) {
    char line[MAXSZ], sname[MAXSZ], country[MAXSZ], hsisno[MAXSZ];
    int a, b, c, d;
    FILE *fIn;
    Data *node;

    // Open the input file.

    fIn = fopen ("file.in", "r");
    if (fIn == NULL) {
        printf ("Cannot open file\n");
        return 1;
    }

    // Process every line.

    while (fgets (line, sizeof(line), fIn) != NULL) {
        // Check line for various problems (too short, too long).

        if (line[0] == '\0') {
            printf ("Line too short\n");
            return 1;
        }

        if (line[strlen (line)-1] != '\n') {
            printf ("Line starting with '%s' is too long\n", line);
            return 1;
        }

        line[strlen (line)-1] = '\0';

        // Scan the individual fields.

        if (sscanf (line, "%s %s %d %d %d %d %s",
            sname, country, &a, &b, &c, &d, hsisno) != 7)
        {
            printf ("Line '%s' didn't scan properly\n", line);
            return 1;
        }

        // Allocate a new node to hold data.

        node = malloc (sizeof (Data));
        if (node == NULL) {
            printf ("Ran out of memory\n");
            return 1;
        }

        node->sname = strdup (sname);
        node->country = strdup (country);
        node->a = a;
        node->b = b;
        node->c = c;
        node->d = d;
        node->hsisno = strdup (hsisno);
        node->next = NULL;
        if (first != NULL) {
            last->next = node;
            last = node;
        } else {
            first = node;
            last = node;
        }
    }

    fclose (fIn);

    // Output the list for debugging.

    node = first;
    while (node != NULL) {
        printf ("'%s' '%s' %d %d %d %d '%s'\n",
            node->sname, node->country, node->a, node->b,
            node->c, node->d, node->hsisno);
        node = node->next;
    }

    return 0;
}

الذي يقرأ في ملفك ويخزنه في قائمة مرتبطة. يخرج:

'Lee' 'AUS' 2 103 2 62 'TRUE'
'Check' 'AUS' 4 48 0 23 'FALSE'
'Mills' 'AUS' 8 236 0 69 'FALSE'

في النهاية ، كما هو متوقع.


لقد قمت بسلسلة كاملة من الإجابات على مخاطر الاستخدام *scanf وظائف على البيانات غير السيطرة (أدخل user:14860 fgets في مربع البحث أعلاه) ، بعضها (هنا, هنا و هنا, ، على سبيل المثال) تشمل وظيفة مفضلة معمرة ، getLine, ، لإدخال المستخدم أكثر أمانًا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top