strcat يلقي خطأ تجزئة على إدخال كلمة مرور تشبه getch البسيطة
-
28-09-2019 - |
سؤال
أنا أستخدم Linux وهناك وظيفة مخصصة لإرجاع ASCII int
من نوع المفتاح الحالي مثل getch()
. عند محاولة التعود عليها وكيفية تخزين كلمة المرور التي وصلت إلى مشكلة ، فإن الكود الخاص بي هو كما يلي:
int main() {
int c;
char pass[20] = "";
printf("Enter password: ");
while(c != (int)'\n') {
c = mygetch();
strcat(pass, (char)c);
printf("*");
}
printf("\nPass: %s\n", pass);
return 0;
}
للأسف أحصل على التحذير من مجلس التعاون الخليجي:
pass.c:26: warning: passing argument 2 of ‘strcat’ makes pointer from integer without a cast
/usr/include/string.h:136: note: expected ‘const char * __restrict__’ but argument is of type ‘char’
حاولت استخدام المؤشرات بدلاً من صفيف char للمرور ، ولكن في الثانية أنا أكتب حرفًا يتصاعد. تعمل الوظيفة من تلقاء نفسها ولكن ليس في الحلقة ، فلا تشبه GetCh () على نظام Windows.
ما الذي يمكنك رؤيته خطأ في مثالي؟ أنا أستمتع بتعلم هذا.
تعديل: بفضل الإجابات التي توصلت إليها بالرمز السخيف التالي:
int c;
int i = 0;
char pass[PASS_SIZE] = "";
printf("Enter password: ");
while(c != LINEFEED && strlen(pass) != (PASS_SIZE - 1)) {
c = mygetch();
if(c == BACKSPACE) {
//ensure cannot backspace past prompt
if(i != 0) {
//simulate backspace by replacing with space
printf("\b \b");
//get rid of last character
pass[i-1] = 0; i--;
}
} else {
//passed a character
pass[i] = (char)c; i++;
printf("*");
}
}
pass[i] = '\0';
printf("\nPass: %s\n", pass);
المحلول
المشكلة هي strcat
يتوقع char *
كحجة ثانية لها (تسلس سلسلتين). ليس لديك سلاسلان ، لديك سلسلة واحدة وواحدة char
.
إذا كنت تريد إضافة c
حتى نهاية pass
, ، فقط احتفظوا i
الذي يخزن الحجم الحالي لـ pass
ثم افعل شيئًا مثل
pass[i] = (char) c
.
تأكد pass
عند الانتهاء (عن طريق تحديد الموضع الأخير إلى 0).
نصائح أخرى
حرف واحد ليس هو نفس سلسلة تحتوي على حرف واحد.
وبعبارة أخرى ، "أ" و "أ" أشياء مختلفة جدا.
السلسلة ، في C ، هي مجموعة من chars المنتهية الفارغة. "Pass" الخاص بك عبارة عن مجموعة من 20 Chars - كتلة من الذاكرة تحتوي على مساحة 20 Chars.
وظيفة mygetch () إرجاع char.
ما عليك القيام به هو إدراج C في أحد المساحات.
بدلاً من "strcat (pass ، c)" ، تريد القيام به "تمرير [i] = c" ، حيث أبدأ في الصفر ، وزيادات واحدة لكل مرة تتصل بها mygetch ().
ثم تحتاج إلى إجراء تمريرة [i] = ' 0' ، عندما يتم الانتهاء من الحلقة ، مع تساوي عدد المرات التي اتصلت بها mygetch () ، لإضافة Terminator NULL.
لديك مشكلة أخرى هي أنك لم تقم بتعيين قيمة لـ C ، في المرة الأولى التي تقوم فيها بالتحقق لمعرفة ما إذا كانت " n". تريد الاتصال mygetch () قبل إجراء المقارنة:
int i = 0;
for (;;)
{
c = mygetch();
if (c == '\n')
break;
c = mygetch();
pass[i++] = c;
}
pass[i] = '\0';
علاوة على المشكلة التي تم تشخيصها بشكل صحيح مع strcat()
أخذ سلسلتين - لماذا تجاهلت التحذيرات المترجم ، أو إذا لم تكن هناك تحذيرات ، فلماذا لم يتم تشغيل تحذيرات؟ كما كنت أقول ، علاوة على هذه المشكلة ، تحتاج أيضًا إلى التفكير في ما يحدث إذا حصلت على EOF ، وتحتاج أيضًا إلى القلق بشأن القيمة الأولية لـ "C" (والتي يمكن أن تكون عن طريق الخطأ " n" على الرغم من أنها على الأرجح 'ر).
هذا يؤدي إلى كود مثل هذا:
int c;
char pass[20] = "";
char *end = pass + sizeof(pass) - 1;
char *dst = pass;
while ((c = getchar()) != EOF && c != '\n' && dst < end)
*dst++ = c;
*dst = '\0'; // Ensure null termination
لقد تحولت من "mygetch ()" إلى "getchar ()" - في المقام الأول لأن ما أقوله ينطبق على ذلك وقد لا ينطبق على وظيفة "mygetch () ؛ ليس لدينا مواصفات لما تفعله هذه الوظيفة على EOF.
بدلاً من ذلك ، إذا كان يجب عليك استخدامه strcat()
, ، لا تزال بحاجة إلى متابعة مسار على طول السلسلة ، ولكن يمكنك القيام بذلك:
char c[2] = "";
char pass[20] = "";
char *end = pass + sizeof(pass) - 1;
char *dst = pass;
while (c[0] != '\n' && dst < end)
{
c[0] = mygetch();
strcat(dst, c);
dst++;
}
ليست أنيقة مثل كل ذلك - باستخدام strcat()
في السياق مبالغة. يمكنك ، على ما أظن ، القيام بالعد البسيط واستخدامها مرارًا وتكرارًا strcat(pass, c)
, ، لكن هذا له سلوك تربيعي strcat()
يجب أن تتخطى 0 ، 1 ، 2 ، 3 ، ... الشخصيات على التكرارات اللاحقة. على النقيض من ذلك ، فإن الحل الذي يشير فيه DST إلى NUL في نهاية السلسلة يعني ذلك strcat()
ليس من الضروري تخطي أي شيء. مع إضافة حجم ثابت من حرف واحد ، رغم ذلك ، من المحتمل أن تكون أفضل حالًا مع الحلقة الأولى.