سؤال

أرغب في مسح المتغيرات التي تشكل ناقلات من ملف نصي محدد للمساحة البيضاء وكتلة العثرة (كلها في كثير من الأحيان بالنسبة لي) هي الافتقار إلى الأناقة.

حاليًا يتطلب رمز المسح الخاص بي تحديد حجم المتجه كعنصر أول في الملف:

7 : 1 3 6 8 -9 .123 1.1

وهو ما يزعجني لأنه يمكن تحديد "7" من خلال فحص المساحة البيضاء.

لقد جربت أشكالًا مختلفة من FSCANF () ، strtok () وما إلى ذلك ، ولكن يبدو أن كل شيء غاشم. دون اللجوء إلى LEX/YACC (غير متوفر) هل يمكن لشخص ما أن يقترح شيئًا أكثر أناقة من ما يلي؟

typedef struct vector_tag
{
    int Length;
    double * value;
} vector;

vector v;

char buf[BIG_ENOUGH], key[BIG_ENOUGH], val[BIG_ENOUGH];

void scan_vector(FILE * fh)
{
    int i, length;
    double * data;
    char * tok;

    do {
        if (feof(fh)) return;
        fgets(buf, sizeof buf, fh);    
    } while (2 != sscanf(buf,"%[^:]:%[^\n\r]",key,val));

    length      =
    v.Length    = strtol(key,NULL,10);
    data        =
    v.value     = malloc(length * sizeof(double));

    tok = strtok(val, " "); /* I'd prefer tokenizing on whitespace */
    for (i = 0; i++ < v.Length; ) {
        * data++ = strtod(tok,NULL);;
        tok = strtok(NULL, " "); /* Again, tokenize on whitespace */
    }
}

الحل: بفضل الإجابة التي تم فحصها ، قمت بتنفيذها:

static int scan_vector(FILE * fh, vector * v)
{
    if (1 == fscanf(fh,"%d:",& v->length))
    {
        int         i;

        v->value    = malloc(v->Length * sizeof(double));

        assert (NULL != v->value);

        for (i = 0; i < v->Length; i++)
        {
            if (fscanf(fh,"%lf",v->value + i) != 1) return(0);
        } 
        return(1);
    } 
    return(0);
} /* scan_vector() */
هل كانت مفيدة؟

المحلول

ما الخطأ في شيء مثل:

int scan_vector(FILE *fh)
{
    char pad[2];
    int i;
    if (fscanf(fh,"%d %1[:]", &v.Length, &pad) != 2)
        return -1;
    v.value = malloc(v.Length * sizeof(double));
    for (i = 0; i < v.Length; i++) {
        if (fscanf(fh, "%lf", &v.value[i]) != 1)
            return -1;
    }
    return 0;
}

هذا يحاول قراءة المتجه باستخدام ScanF ، وإرجاع رمز الخطأ -1 إذا كانت هناك مشكلة.

إذا كنت ترغب في القيام بشيء أكثر تعقيدًا من هذا ، فمن المحتمل أن تكون أفضل حالًا باستخدام Flex على الأقل (إن لم يكن البيسون أيضًا).

نصائح أخرى

كما ترى realloc() يمكنك دائمًا طلب المزيد من الذاكرة إذا لم تقم بتخصيص ما يكفي مع الأولي malloc(). والاستراتيجية الشائعة هي تخصيص تعسفي n العناصر للبدء. كلما نفد بعد ذلك من المساحة التي تتضاعف n وتغيير حجم المخزن المؤقت.

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

ما هو حجم المتجهات الخاصة بك؟
طريقة واحدة للذهاب هي ،

  • مسح خط في المخزن المؤقت المحلي (هذه بيانات ناقلات واحدة أفترضها)
  • مسح على هذا المخزن المؤقت المحلي لحساب محددات المساحة البيضاء (من السهل جدًا رمزها)
  • ومن بعد قم بإجراء التخصيص الصحيح
  • وتهيئة المتجه

مثلك تلاحظ ، البعد '7' لا يلزم أن تكون جزءًا من المدخلات.
تحتاج فقط إلى مخزن مؤقت محلي كبير بما يكفي لأطول خط ممكن.
وبعض الأخطاء التعامل معها :-)

إليك نسخة لا تحتاج إلى حجم المتجه كأول إدخال في الملف:

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

#define LINE_MAX 256
#define VECTOR_SIZE_MAX 32

struct vector
{
    size_t size;
    double *values;
};

// returns 1 on error
_Bool scan_vector(FILE *file, struct vector *v)
{
    char buffer[LINE_MAX];
    if(!fgets(buffer, sizeof(buffer), file))
        return 1;

    double values[VECTOR_SIZE_MAX];

    size_t size = 0;
    errno = 0;

    for(char *head = buffer, *tail = NULL;; ++size, head = tail)
    {
        while(isspace(*head)) ++head;
        if(!*head) break;

        if(size >= VECTOR_SIZE_MAX)
            return 1;

        values[size] = strtod(head, &tail);
        if(errno || head == tail)
            return 1;
    }

    v->size = size;
    v->values = malloc(sizeof(double) * size);
    if(!v->values) return 1;

    memcpy(v->values, values, sizeof(double) * size);

    return 0;
}

int main(void)
{
    struct vector v;
    while(!scan_vector(stdin, &v))
    {
        printf("value count: %u\n", (unsigned)v.size);
        free(v.values);
    }

    return 0;
}

يتم إصلاح الحد الأقصى لحجم الخط وعدد الإدخالات من أسباب الأداء والكسل.

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