سؤال

أنا أكتب برنامجًا يعمل مع الملفات. يجب أن أكون قادرًا على إدخال البيانات كهياكل ، وقراءتها في النهاية. المشكلة التي أواجهها في الوقت الحالي مع هذا الرمز:

typedef struct {
    char* name;
    .....
}employeeRecord;
employeeRecord record;

char name[50];

if(choice == 1)
    {
        /*Name*/
        printf("\nEnter the name:");
        fgets(name,50,stdin);
        record.nameLength = strlen(name) -1;
        record.name = malloc(sizeof(char)*record.nameLength);
        strcpy(record.name,name);
        /*Other data, similar format...*/

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

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

المحلول

جربت الكود الخاص بك ولا يمكنني إعادة إنتاج المشكلة. يعمل الرمز التالي بالطريقة التي تتوقعها ، فهو يطالب بالاسم ، وانتظر لك أن تكتب الاسم ، ثم يطالب بالعنوان ، إلخ.

أنا أتساءل عما إذا كنت لا تحتاج إلى قراءة Stdin وتفريغها قبل المطالبة بمزيد من الإدخال؟

typedef struct {
    char* name;
    char* address;
}employeeRecord;

int readrecord(employeeRecord &record)
{
   char name[50];
   char address[100];

   printf("\nenter the name:");
   fgets(name, sizeof(name), stdin);
   record.nameLength = strlen(name) + 1;
   record.name = malloc(sizeof(char)*record.nameLength);
   strcpy(record.name,name);

   printf("\nenter the address:");
   fgets(address, sizeof(address), stdin);

   ...    
}

من المؤكد ، تريد إضافة 1 إلى Strlen (الاسم) ، وليس طرح 1. أو ، إذا كنت تريد تخزين الاسم في السجل الخاص بك دون إنهاء خالية ، فأنت بحاجة إلى استخدام Memcpy لنسخ السلسلة في السجل الخاص بك ، وليس strcpy.

تعديل:

أرى من التعليقات التي تستخدمها scanf لقراءة قيمة الاختيار ، فإن هذا يترك n في المخزن المؤقت للإدخال والذي يتم التقاطه بعد ذلك بواسطة fgets يتصل. ما يجب عليك فعله بدلاً من ذلك هو استخدام FGTS لقراءة في خط الاختيار ، ثم SSCANF لتحليل القيمة من الإدخال. مثله

int choice;
char temp[50];
fgets(temp, sizeof(temp), stdin);
sscanf(temp, "%d", &choice);

من شأن ذلك أن يجعل قضية Flushing Stdin Moot.

نصائح أخرى

لا يزال الخط الجديد موجودًا stdin من مكالمة سابقة إلى وظيفة لم تقرأ خطًا جديدًا من الإدخال. واضح stdin من خلال القراءة حتى تقرأ الخط الجديد - ليس عن طريق التدفق stdin كما اقترح آخرون.

تحرير: شكرا ألوك ، على التصحيح!

ربما تستخدم scanf ليقرأ choice قبل الاتصال fgets لقراءة الاسم. scanf ربما تركت خطًا جديدًا في stdin أي أخطاء رمزك لإدخال اسم فارغ. إذا كان هذا هو الحال بالفعل ، فحاول ألا تستخدم scanf (استعمال fgets لأسترجاع choice والاستخدام atoi للتحول إلى int أو strcmp للمقارنة مع "1 n" وما إلى ذلك). يجب أن يعمل الرمز بطريقة أخرى ، مع التعديلات أدناه لحساب حقيقة أن fgets يقرأ أيضًا خط الإنهاء الجديد في المخزن المؤقت (الذي ربما تريد تجريده):

  #define MY_LENOF(x) (sizeof(x)/sizeof((x)[0])) 

  char choice[3] = { 0 }; /* example of how to initialize to all NULs */
  if (!fgets(choice, MY_LENOF(choice), stdin)) {
    fprintf(stderr, "Premature end of input\n");
    exit(1);
  }

  if (strcmp(choice, "1\n") == 0) {  
    /*Name*/
    printf("\nEnter the name:");
    if (!fgets(name, MY_LENOF(name), stdin)) {
      /* if fgets fails it leaves name unchanged, so we reset it to "" */
      name[0] = '\0';
    }
    /* good practice to use srtnlen in order not to overrun fixed buffer */
    /*  not necessarily a problem with fgets which guarantees the trailing NUL */
    size_t nameLength = strnlen(name, MY_LENOF(name));
    assert(name[nameLength] == '\0');
    if (nameLength - 1 > 0 && name[nameLength - 1] == '\n') {
      /* strip trailing newline */
      name[--nameLength] = '\0';
    } else if (nameLength >= MY_LENOF(name) - 1) {
      fprintf(stderr, "Name is too long\n");
      exit(1);
    } else {
      fprintf(stderr, "Premature end of input\n");
      exit(1);
    }

    record.nameLength = nameLength;
    record.name = malloc(sizeof(char)*(record.nameLength + 1));
    strcpy(record.name, name);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top