سؤال سريع فيما يتعلق بهذه المشكلة، لماذا لا يطبع القيمة الثانية (القيمة الثانية المحولة) على السلسلة؟

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

  •  18-09-2019
  •  | 
  •  

سؤال

سؤال سريع، ماذا فعلت خطأ هنا. الغرض من هذا الرمز هو الحصول على المدخلات في سلسلة، والإدخال يجري "12 34"، مع مساحة بين "12" و "32" وتحويل وطباعة الأرقام المنفصلة اثنين من متغير عدد صحيح يعرف باسم رقم. لماذا لا تتطلب الدعوة الثانية إلى وظيفة CopyTemp، لا تنتج القيمة 34؟ لدي متغير index_counter الذي يحافظ على تتبع مؤشر السلسلة ومقصوده لتخطي شخصية "الفضاء"؟ مالخطأ الذي فعلته؟

شكرا.

#include <stdio.h>
#include <string.h>
int index_counter = 0;
int number;
void copyTemp(char *expr,char *temp);

int main(){
 char exprstn[80]; //as global?
 char tempstr[80];

 gets(exprstn);
 copyTemp(exprstn,tempstr);
 printf("Expression: %s\n",exprstn);
 printf("Temporary: %s\n",tempstr);
 printf("number is: %d\n",number);
 copyTemp(exprstn,tempstr);      //second call produces same output shouldnt it now produce 34 in the variable number?
 printf("Expression: %s\n",exprstn);
 printf("Temporary: %s\n",tempstr);
 printf("number is: %d\n",number);

 return 0;
}
void copyTemp(char *expr,char *temp){
 int i;
 for(i = index_counter; expr[i] != '\0'; i++){
  if (expr[i] == '0'){
   temp[i] = expr[i];
  }
  if (expr[i] == '1'){
   temp[i] = expr[i];
  }
  if (expr[i] == '2'){
   temp[i] = expr[i];
  }
  if (expr[i] == '3'){
   temp[i] = expr[i];
  }
  if (expr[i] == '4'){
   temp[i] = expr[i];
  }
  if (expr[i] == '5'){
   temp[i] = expr[i];
  }
  if (expr[i] == '6'){
   temp[i] = expr[i];
  }
  if (expr[i] == '7'){
   temp[i] = expr[i];
  }
  if (expr[i] == '8'){
   temp[i] = expr[i];
  }
  if (expr[i] == '9'){
   temp[i] = expr[i];
  }
  if (expr[i] == ' '){ 
   temp[i] = '\0';
   sscanf(temp,"%d",&number); 
   index_counter = i+1; //skips?
  }
 }
 // is this included here? temp[i] = '\0'; 
}
هل كانت مفيدة؟

المحلول

هناك بعض المشاكل في البرنامج الخاص بك:

  • أنت تستخدم نفس الفهرسexpr و temp صفائف. هذا يعمل لأول مرة منذ أن سيكون كلاهما 0لتبدأ ولكن عندما تريد معالجة 2nd رقم، تحتاج إلى إعادة تعيين الفهرس إلى temp صفيف العودة إلى 0. وبعد من الواضح أنه لا يمكن القيام بذلك باستخدام فهرس واحد. سيكون عليك استخدام مؤشرين، i و j.
  • بحلول الوقت الذي تكمل فيه معالجة الرقم الثاني ( 34 في"12 34") سوف تصل إلى نهاية السلسلة وبالتالي sscanf لا تجري أبدا في المناسبة الثانية (بشكل عام للمناسبة الأخيرة). لذلك بعد حلقة تحتاج إلى SSCANF أخرى لاستخراج الرقم الأخير. كما يجب أن تعود من الوظيفة بمجرد استخراج الرقم من السلسلة وزيادة أنا.
  • يجب تجنب استخدام gets() واستخدامfgets() بدلا من ذلك بسبب الأسباب الأمنية.
  • يمكنك الجمع بين الاختبار المتعدد للأرقام في اختبار واحد كما هو موضح:

شيء من هذا القبيل.

void copyTemp(char *expr,char *temp){
    int i;
    int j = 0;
    for(i = index_counter; expr[i] != '\0'; i++){

        if (expr[i] >= '0' && expr[i]<='9'){
            temp[j++] = expr[i]; // copy the digit into temp..increment j.
        }    
        else if (expr[i] == ' '){ // space found..time to extract number.
            temp[j] = '\0'; // terminate the temp.
            sscanf(temp,"%d",&number); // extract.
            index_counter = i+1; // skip the space.
                    return; // done converting...return..must not continue.
        }
    }
    // have reached the end of the input string..and still need to extract a 
    // the last number from temp string.
    temp[j] = '\0';
    sscanf(temp,"%d",&number);
}

بعد هذه التغييرات تعمل كما هو متوقع:

$ gcc b.c 2> /dev/null && ./a.out
12 34
Expression: 12 34
Temporary: 12
number is: 12
Expression: 12 34
Temporary: 34
number is: 34

نهجك هش للغاية ... إذا كان المستخدم يعطي مسافات متعددة بين أرقام الإدخال .. سوف يفشل برنامجك.

نصائح أخرى

المشكلة الرئيسية هي ذلك copyTemp يكتب إلى temp[i], ، ولكن كل مكالمة إلى copyTemp تهيئة i ل index_counter, ، وليس ل 0. وهذا يعني أن كل مكالمة إلى copyTemp يلفظ إلى القائمة temp المخزن المؤقت بدلا من الكتابة فوق المحتويات القديمة، و sscanf وبالتالي دائما إعادة قراءة نفس السلسلة. تحتاج إلى استخدام مؤشرات منفصلة لتتبع مكان القراءة من المخزن المؤقت الإدخال وأين تكتب إلى مخزن المؤقت الإخراج.

مشاكل إضافية: * لا تستخدم أبدا ggets. أي وقت مضى. وبعد يستخدم fgets في حين أن. * يمكنك تكرار الكثير من التعليمات البرمجية copyTemp. وبعد يمكنك بدلا من ذلك القيام به:

if (expr[i] == '0' || expr[i] == '1' || ...)

أو أفضل:

if (isdigit(expr[i]))
  • copyTemp يجب أن تتخذ بعض الاحتياطات اللازمة لعدم تجاوز المخزن المؤقت الوجهة. (لاحظ أن copyTemp يجب أن لا تحتاج حتى إلى أخذ مخزن مؤقت وجهة كوسيطة.)

  • يجب تجنب استخدام المتغيرات العالمية. سيكون أفضل ل copyTemp لاتخاذ حجة لتحديد مكان بدء القراءة من سلسلة الإدخال وإعادة الفهرس حيث توقفت.

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