سؤال سريع فيما يتعلق بهذه المشكلة، لماذا لا يطبع القيمة الثانية (القيمة الثانية المحولة) على السلسلة؟
سؤال
سؤال سريع، ماذا فعلت خطأ هنا. الغرض من هذا الرمز هو الحصول على المدخلات في سلسلة، والإدخال يجري "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
لاتخاذ حجة لتحديد مكان بدء القراءة من سلسلة الإدخال وإعادة الفهرس حيث توقفت.