运行 个 C 程序后未定义的计算机行为
Undefined computer behavior after running a C program
我开门见山了,因为我无法解释我要描述的情况。我需要你的关注!
昨天我用C写了一个程序,程序输入一个字符串,如果这个字符串是"PKPKKKPPPKKKP"这种形式,即只包含'P'和'K' 字符它会打印 YES 或 NO。 YES 如果单个 'P' 字符与 'K' 字符匹配。就像我们处理括号字符问题 '(', ')' 一样,只是我不得不使用 'P' 而不是 ')',而不是 '(','K'.
在此处的一点帮助下,我设法完成了该程序,并且 运行ning 正确。我不认为复制代码会对任何人有帮助,但我会解释它是如何工作的。
程序说明:
该程序以一个字符串(字符串可以达到 500 长度)作为输入,如果该字符串仅包含 'P' 和 'K' 字符,则打印 YES 或 NO ,正如我上面所描述的,否则它会拒绝它。然后它逐个字符读取输入,当它找到 'P' 时将其压入堆栈,否则弹出。 (我用链表实现了堆栈,所以用户可以给出他想要的任意大的字符串(或者我这么认为......))。
在用户键入字符串之前,符号 'A' 位于堆栈中。所以输入是由程序逐个字符分析的,如果它找到一个 'P' 它被推入堆栈,否则弹出堆栈。如果最后的堆栈顶部是 'A' 字符,则程序打印 YES,否则打印 NO。
问题描述:
所以我今天和我的一个朋友一起表演这个节目。一切都很好。直到我将一个非常大的字符串作为输入传递,例如 300'P's 和 300'K's(记住我的字符串是一个 char string[500])。它打印是。然后我输入了一个像 800'P's+800'K's 这样的字符串。它没有 运行 正确。
这就是问题所在,在那次事件之后,无论我输入一个字符串,一个普通的字符串 "PKPKPK",它都会打印出数百万个奇怪的符号( x └ X ╨ x └ X ╨ x )。我没有碰代码,我发誓!我又编译了一遍,运行,还是一样!我的电脑好像出了点问题 (Windows 10)。
问题继续到另一个程序......我试图制作一个简单的程序来运行用链表实现的堆栈。我推了字符 'a' 并打印出来。它打印'á'。我推了'b'。它打印 'h'。我推了'd'。它打印 'L'.
显然我不应该输入这么大的字符串,因为它的长度限制是500。但问题仍然存在!我不能再用链表编写程序了。我很绝望!
代码:
#include "stdio.h"
#define FIRST_SYMBOL_IN_STACK 'A'
#define TRUE 1
#define FALSE 0
#define STR_LENGTH 50
#define YES "YES"
#define NO "NO"
#define PLA 'P'
#define KAL 'K'
typedef struct node {
char simvolo_eisodou;
struct node *next;
} node;
node *top = NULL; // the top of the stack
void push(char simvolo_eisodou); //stack function
int isStackEmpty(); //stack function
void pop(); //stack function
void printStack(); //print the current stack elements
int isInputValid(char *string);
void printWelcome();
int main() {
char input_string[STR_LENGTH], apantisi = 'G'; //O xristis mporei na dwsei input_string mikous ews 500 xaraktires
push(FIRST_SYMBOL_IN_STACK);
int i = 0;
scanf("%s", input_string);
if (isInputValid(input_string)) {
while (input_string[i] != '[=11=]') {
if (input_string[i] == PLA) {
push(PLA);
printStack();
} else {
pop();
printStack();;
}
i++;
}
} else {
printf("Den anagnwristike to %s, input_string=(P|K)*\n");
_exit(-1);
}
if (top->simvolo_eisodou == FIRST_SYMBOL_IN_STACK) {
printf("%s\n", YES);
} else {
printf("%s\n", NO);
}
return 0;
}
void push(char simvolo_eisodou) {
node *newNode = (node*)malloc(sizeof(node));
newNode->simvolo_eisodou = simvolo_eisodou;
newNode->next = top;
top = newNode;
free(newNode);
}
int isStackEmpty() { //Thewrw oti i stoiva einai adeia otan i korifi einai to arhiko simvolo
if (top->simvolo_eisodou == FIRST_SYMBOL_IN_STACK) {
return TRUE;
}
return FALSE;
}
void pop( ){
if (isStackEmpty()) {
printf("KENO\n");
printf("%s\n", NO);
_exit(-1);
}
node *temp = top;
top = top->next;
free(temp);
}
void printStack() {
node *current = top;
while (current != NULL) {
printf("%c ", current->simvolo_eisodou);
current = current->next;
}
free(current);
printf("\n");
}
int isInputValid(char *string) {
int i = 0;
while (*(string + i) != '[=11=]') {
if (!(*(string + i) == 'P' || *(string + i) == 'K')) {
return 0;
}
++i;
}
return 1;
}
void printWelcome() {
printf("\n====================================================================\n");
printf("Welcome\n");
printf("====================================================================\n");
printf("\n\n\n Plz type input_string=(P|K)*\n");
}
您的代码开头为:
#define STR_LENGTH 50
// ... in main
char input_string[STR_LENGTH];
scanf("%s", input_string);
在您的问题中,您谈到了长度为 500
的缓冲区。但是你的代码中没有这个buffer,长度是50
.
如果您输入 50 个或更多字符,则会导致 undefined behaviour。这意味着 任何事情都可能发生。您无法控制在这种情况下发生的事情,您不应期望任何特定行为。
唯一解决问题的方法是停止缓冲区溢出。您必须更改代码以防止溢出。
你的程序描述是它应该支持最多 500 个字符的字符串。实现这一目标的一种方法是:
char input_string[501]; // +1 for terminator
scanf("%500s", input_string); // IMPORTANT: 500 limiter
如果你想在他们输入过多时报告错误,而不是忽略它,你可以这样写:
if ( !isspace(getchar()) ) // requires #include <ctype.h>
{
fprintf(stderr, "Too many characters entered - aborting program");
exit(EXIT_FAILURE);
}
例如。
如果你真的想支持任意长度的输入,那么你需要切换到更复杂的内存策略(例如,链表,或随着输入的增长重新分配缓冲区)。
关于您的代码的其他注释:
- 您使用了
#include <stdlib.h>
中的函数,所以您必须有那一行
printf("Den anagnwristike to %s, input_string=(P|K)*\n")
有一个 %s
但没有对应的参数,这也会导致未定义的行为
- 使用
exit(EXIT_FAILURE)
代替_exit(-1);
注意。可能还有其他问题,我没有检查你的整个程序。
您的代码存在未定义行为 (UB)。使用 UB 的 运行 代码的结果是不可预测的。它有时似乎有效,但不能保证每次都会出现相同的结果。
您的 UB 的至少一个来源是此代码:
top=newNode;
free(newNode);
一旦 newNode
被释放,top
指针将变得无效,对该指针的任何取消引用都将导致 UB。
我开门见山了,因为我无法解释我要描述的情况。我需要你的关注!
昨天我用C写了一个程序,程序输入一个字符串,如果这个字符串是"PKPKKKPPPKKKP"这种形式,即只包含'P'和'K' 字符它会打印 YES 或 NO。 YES 如果单个 'P' 字符与 'K' 字符匹配。就像我们处理括号字符问题 '(', ')' 一样,只是我不得不使用 'P' 而不是 ')',而不是 '(','K'.
在此处的一点帮助下,我设法完成了该程序,并且 运行ning 正确。我不认为复制代码会对任何人有帮助,但我会解释它是如何工作的。
程序说明: 该程序以一个字符串(字符串可以达到 500 长度)作为输入,如果该字符串仅包含 'P' 和 'K' 字符,则打印 YES 或 NO ,正如我上面所描述的,否则它会拒绝它。然后它逐个字符读取输入,当它找到 'P' 时将其压入堆栈,否则弹出。 (我用链表实现了堆栈,所以用户可以给出他想要的任意大的字符串(或者我这么认为......))。 在用户键入字符串之前,符号 'A' 位于堆栈中。所以输入是由程序逐个字符分析的,如果它找到一个 'P' 它被推入堆栈,否则弹出堆栈。如果最后的堆栈顶部是 'A' 字符,则程序打印 YES,否则打印 NO。
问题描述: 所以我今天和我的一个朋友一起表演这个节目。一切都很好。直到我将一个非常大的字符串作为输入传递,例如 300'P's 和 300'K's(记住我的字符串是一个 char string[500])。它打印是。然后我输入了一个像 800'P's+800'K's 这样的字符串。它没有 运行 正确。 这就是问题所在,在那次事件之后,无论我输入一个字符串,一个普通的字符串 "PKPKPK",它都会打印出数百万个奇怪的符号( x └ X ╨ x └ X ╨ x )。我没有碰代码,我发誓!我又编译了一遍,运行,还是一样!我的电脑好像出了点问题 (Windows 10)。 问题继续到另一个程序......我试图制作一个简单的程序来运行用链表实现的堆栈。我推了字符 'a' 并打印出来。它打印'á'。我推了'b'。它打印 'h'。我推了'd'。它打印 'L'.
显然我不应该输入这么大的字符串,因为它的长度限制是500。但问题仍然存在!我不能再用链表编写程序了。我很绝望!
代码:
#include "stdio.h"
#define FIRST_SYMBOL_IN_STACK 'A'
#define TRUE 1
#define FALSE 0
#define STR_LENGTH 50
#define YES "YES"
#define NO "NO"
#define PLA 'P'
#define KAL 'K'
typedef struct node {
char simvolo_eisodou;
struct node *next;
} node;
node *top = NULL; // the top of the stack
void push(char simvolo_eisodou); //stack function
int isStackEmpty(); //stack function
void pop(); //stack function
void printStack(); //print the current stack elements
int isInputValid(char *string);
void printWelcome();
int main() {
char input_string[STR_LENGTH], apantisi = 'G'; //O xristis mporei na dwsei input_string mikous ews 500 xaraktires
push(FIRST_SYMBOL_IN_STACK);
int i = 0;
scanf("%s", input_string);
if (isInputValid(input_string)) {
while (input_string[i] != '[=11=]') {
if (input_string[i] == PLA) {
push(PLA);
printStack();
} else {
pop();
printStack();;
}
i++;
}
} else {
printf("Den anagnwristike to %s, input_string=(P|K)*\n");
_exit(-1);
}
if (top->simvolo_eisodou == FIRST_SYMBOL_IN_STACK) {
printf("%s\n", YES);
} else {
printf("%s\n", NO);
}
return 0;
}
void push(char simvolo_eisodou) {
node *newNode = (node*)malloc(sizeof(node));
newNode->simvolo_eisodou = simvolo_eisodou;
newNode->next = top;
top = newNode;
free(newNode);
}
int isStackEmpty() { //Thewrw oti i stoiva einai adeia otan i korifi einai to arhiko simvolo
if (top->simvolo_eisodou == FIRST_SYMBOL_IN_STACK) {
return TRUE;
}
return FALSE;
}
void pop( ){
if (isStackEmpty()) {
printf("KENO\n");
printf("%s\n", NO);
_exit(-1);
}
node *temp = top;
top = top->next;
free(temp);
}
void printStack() {
node *current = top;
while (current != NULL) {
printf("%c ", current->simvolo_eisodou);
current = current->next;
}
free(current);
printf("\n");
}
int isInputValid(char *string) {
int i = 0;
while (*(string + i) != '[=11=]') {
if (!(*(string + i) == 'P' || *(string + i) == 'K')) {
return 0;
}
++i;
}
return 1;
}
void printWelcome() {
printf("\n====================================================================\n");
printf("Welcome\n");
printf("====================================================================\n");
printf("\n\n\n Plz type input_string=(P|K)*\n");
}
您的代码开头为:
#define STR_LENGTH 50
// ... in main
char input_string[STR_LENGTH];
scanf("%s", input_string);
在您的问题中,您谈到了长度为 500
的缓冲区。但是你的代码中没有这个buffer,长度是50
.
如果您输入 50 个或更多字符,则会导致 undefined behaviour。这意味着 任何事情都可能发生。您无法控制在这种情况下发生的事情,您不应期望任何特定行为。
唯一解决问题的方法是停止缓冲区溢出。您必须更改代码以防止溢出。
你的程序描述是它应该支持最多 500 个字符的字符串。实现这一目标的一种方法是:
char input_string[501]; // +1 for terminator
scanf("%500s", input_string); // IMPORTANT: 500 limiter
如果你想在他们输入过多时报告错误,而不是忽略它,你可以这样写:
if ( !isspace(getchar()) ) // requires #include <ctype.h>
{
fprintf(stderr, "Too many characters entered - aborting program");
exit(EXIT_FAILURE);
}
例如。
如果你真的想支持任意长度的输入,那么你需要切换到更复杂的内存策略(例如,链表,或随着输入的增长重新分配缓冲区)。
关于您的代码的其他注释:
- 您使用了
#include <stdlib.h>
中的函数,所以您必须有那一行 printf("Den anagnwristike to %s, input_string=(P|K)*\n")
有一个%s
但没有对应的参数,这也会导致未定义的行为- 使用
exit(EXIT_FAILURE)
代替_exit(-1);
注意。可能还有其他问题,我没有检查你的整个程序。
您的代码存在未定义行为 (UB)。使用 UB 的 运行 代码的结果是不可预测的。它有时似乎有效,但不能保证每次都会出现相同的结果。
您的 UB 的至少一个来源是此代码:
top=newNode;
free(newNode);
一旦 newNode
被释放,top
指针将变得无效,对该指针的任何取消引用都将导致 UB。