在 C 中使用 ncurses 的 wrefresh 函数时出现分段错误
Segmentation Fault while using wrefresh function of ncurses in C
首先,我用 ncurses 创建了两个 windows:一个用于传输,一个用于接收。基本上,一个写命令,另一个打印命令。为了在接收 window 中写入输入,我做了一个小函数来连接接收中已有的字符串 window 和用户编写的字符串(我认为问题就在那里)。
因此,当我 运行 代码时,程序失败并显示在 wrefresh(winReception);
行转储的分段错误代码
但奇怪的是,如果输入是 7 个或更少的字符,它可以工作,如果它是 8 个或更多,它就会中断。
我正在使用 Code::Blocks
此处截图:https://imgur.com/a/zEwBs1k
这是一些代码:
//Global variables
WINDOW * winReception;
WINDOW * winTransmission;
char * command;
char mesg[] = "Enter a command";
//variable to stock the input in reception window
char *textinwindow = "";
//main
int main(int argc, char* argv[])
{
initscr();
/* WINDOW RECEPTION */
winReception = newwin(15, 0, 0, 0);
wrefresh(winReception);
/* WINDOW TRANSMISSION*/
winTransmission= newwin(8, 0, 15, 0);
wrefresh(winTransmission);
mvwprintw(winTransmission, 1, 2, mesg);
wgetstr(winTransmission, &command);
verifInput(&command);
free(textinwindow);
exit(0);
}
//concat function (where I think the bug is)
char* concat(char *s1, char *s2)
{
char *result = (char *) malloc(strlen(s1) + strlen(s2) + 1);
strcpy(result, s1);
strcat(result, "\n ");
strcat(result, s2);
return result;
}
//verifInput (where the program fails)
void verifInput (char* cmd)
{
/* WINDOW RECEPTION */
textinwindow = concat(textinwindow, cmd);
mvwprintw(winReception, 1, 2, textinwindow);
wrefresh(winReception);
/* WINDOW TRANSMISSION*/
touchwin(winTransmission);
wclear(winTransmission);
wrefresh(winTransmission); //Program fails here
mvwprintw(winTransmission, 1, 2, mesg);
wgetstr(winTransmission, &command);
verifInput(&command);
}
如评论中所述,这里存在许多问题,但主要问题是 wgetstr()
的完全错误使用,因为它接受用户的输入并将其填充到缓冲区中,但你有没有分配缓冲区。我们不知道 command
的值是多少,所以它正在将数据存储到随机内存中。
错误的解决方法是:
char command[256];
wgetstr(winTransmission, command); // NO
因为虽然你会提供一个地方来存储用户的输入,wgetstr()
不知道缓冲区有多大,如果用户输入太多,它会覆盖那里的内存也。不好。
相反,我们将使用带缓冲区 和计数
的有界版本 wgetnstr()
char command[256];
wgetnstr(winTransmission, command, sizeof command); // YES
现在它永远不会覆盖缓冲区!
其他问题:尽管您在代码末尾释放了 textinwindow
内存,但每次调用 concat()
时 old 值textinwindow
- 这也是分配的内存 - 被扔掉了。那肯定是内存泄漏。
最后,一个微妙的问题。由于 mvwprintw()
采用 printf 样式的格式字符串,因此您传递给它的值来自用户并且可能包含 %s
标记。这没有好处。相反:
mvwprintw(winReception, 1, 2, "%s", textinwindow);
这意味着用户输入字符串中任何时髦的 %
都不会造成破坏。
这是我想出的:
#include <stdio.h>
#include <ncurses.h>
#include <string.h>
#include <stdlib.h>
//Global variables
WINDOW * winReception;
WINDOW * winTransmission;
char command[256];
const char mesg[] = "Enter a command";
//variable to stock the input in reception window
char *textinwindow = 0;
void verifInput (const char* cmd);
//main
int main(int argc, char* argv[])
{
initscr();
/* WINDOW RECEPTION */
winReception = newwin(15, 0, 0, 0);
wrefresh(winReception);
/* WINDOW TRANSMISSION*/
winTransmission= newwin(8, 0, 15, 0);
wrefresh(winTransmission);
mvwprintw(winTransmission, 1, 2, mesg);
wgetnstr(winTransmission, command, sizeof command);
verifInput(command);
free(textinwindow);
exit(0);
}
//concat function (where I think the bug is)
char* concat(const char *s1, const char *s2)
{
// 2 = newline + space
// 1 = final NUL byte
char *result = (char *) malloc(strlen(s1) + 2 + strlen(s2) + 1);
strcpy(result, s1);
strcat(result, "\n ");
strcat(result, s2);
return result;
}
//verifInput (where the program fails)
void verifInput (const char* cmd)
{
// free up old memory except for the first time
if (textinwindow == 0)
textinwindow = concat("", cmd);
else
{
char *save = textinwindow;
textinwindow = concat(textinwindow, cmd);
free(save);
}
/* WINDOW RECEPTION */
mvwprintw(winReception, 1, 2, "%s", textinwindow);
wrefresh(winReception);
/* WINDOW TRANSMISSION*/
touchwin(winTransmission);
wclear(winTransmission);
wrefresh(winTransmission); //Program fails here
mvwprintw(winTransmission, 1, 2, mesg);
wgetnstr(winTransmission, command, sizeof command);
verifInput(command);
}
首先,我用 ncurses 创建了两个 windows:一个用于传输,一个用于接收。基本上,一个写命令,另一个打印命令。为了在接收 window 中写入输入,我做了一个小函数来连接接收中已有的字符串 window 和用户编写的字符串(我认为问题就在那里)。
因此,当我 运行 代码时,程序失败并显示在 wrefresh(winReception);
但奇怪的是,如果输入是 7 个或更少的字符,它可以工作,如果它是 8 个或更多,它就会中断。
我正在使用 Code::Blocks
此处截图:https://imgur.com/a/zEwBs1k
这是一些代码:
//Global variables
WINDOW * winReception;
WINDOW * winTransmission;
char * command;
char mesg[] = "Enter a command";
//variable to stock the input in reception window
char *textinwindow = "";
//main
int main(int argc, char* argv[])
{
initscr();
/* WINDOW RECEPTION */
winReception = newwin(15, 0, 0, 0);
wrefresh(winReception);
/* WINDOW TRANSMISSION*/
winTransmission= newwin(8, 0, 15, 0);
wrefresh(winTransmission);
mvwprintw(winTransmission, 1, 2, mesg);
wgetstr(winTransmission, &command);
verifInput(&command);
free(textinwindow);
exit(0);
}
//concat function (where I think the bug is)
char* concat(char *s1, char *s2)
{
char *result = (char *) malloc(strlen(s1) + strlen(s2) + 1);
strcpy(result, s1);
strcat(result, "\n ");
strcat(result, s2);
return result;
}
//verifInput (where the program fails)
void verifInput (char* cmd)
{
/* WINDOW RECEPTION */
textinwindow = concat(textinwindow, cmd);
mvwprintw(winReception, 1, 2, textinwindow);
wrefresh(winReception);
/* WINDOW TRANSMISSION*/
touchwin(winTransmission);
wclear(winTransmission);
wrefresh(winTransmission); //Program fails here
mvwprintw(winTransmission, 1, 2, mesg);
wgetstr(winTransmission, &command);
verifInput(&command);
}
如评论中所述,这里存在许多问题,但主要问题是 wgetstr()
的完全错误使用,因为它接受用户的输入并将其填充到缓冲区中,但你有没有分配缓冲区。我们不知道 command
的值是多少,所以它正在将数据存储到随机内存中。
错误的解决方法是:
char command[256];
wgetstr(winTransmission, command); // NO
因为虽然你会提供一个地方来存储用户的输入,wgetstr()
不知道缓冲区有多大,如果用户输入太多,它会覆盖那里的内存也。不好。
相反,我们将使用带缓冲区 和计数
的有界版本wgetnstr()
char command[256];
wgetnstr(winTransmission, command, sizeof command); // YES
现在它永远不会覆盖缓冲区!
其他问题:尽管您在代码末尾释放了 textinwindow
内存,但每次调用 concat()
时 old 值textinwindow
- 这也是分配的内存 - 被扔掉了。那肯定是内存泄漏。
最后,一个微妙的问题。由于 mvwprintw()
采用 printf 样式的格式字符串,因此您传递给它的值来自用户并且可能包含 %s
标记。这没有好处。相反:
mvwprintw(winReception, 1, 2, "%s", textinwindow);
这意味着用户输入字符串中任何时髦的 %
都不会造成破坏。
这是我想出的:
#include <stdio.h>
#include <ncurses.h>
#include <string.h>
#include <stdlib.h>
//Global variables
WINDOW * winReception;
WINDOW * winTransmission;
char command[256];
const char mesg[] = "Enter a command";
//variable to stock the input in reception window
char *textinwindow = 0;
void verifInput (const char* cmd);
//main
int main(int argc, char* argv[])
{
initscr();
/* WINDOW RECEPTION */
winReception = newwin(15, 0, 0, 0);
wrefresh(winReception);
/* WINDOW TRANSMISSION*/
winTransmission= newwin(8, 0, 15, 0);
wrefresh(winTransmission);
mvwprintw(winTransmission, 1, 2, mesg);
wgetnstr(winTransmission, command, sizeof command);
verifInput(command);
free(textinwindow);
exit(0);
}
//concat function (where I think the bug is)
char* concat(const char *s1, const char *s2)
{
// 2 = newline + space
// 1 = final NUL byte
char *result = (char *) malloc(strlen(s1) + 2 + strlen(s2) + 1);
strcpy(result, s1);
strcat(result, "\n ");
strcat(result, s2);
return result;
}
//verifInput (where the program fails)
void verifInput (const char* cmd)
{
// free up old memory except for the first time
if (textinwindow == 0)
textinwindow = concat("", cmd);
else
{
char *save = textinwindow;
textinwindow = concat(textinwindow, cmd);
free(save);
}
/* WINDOW RECEPTION */
mvwprintw(winReception, 1, 2, "%s", textinwindow);
wrefresh(winReception);
/* WINDOW TRANSMISSION*/
touchwin(winTransmission);
wclear(winTransmission);
wrefresh(winTransmission); //Program fails here
mvwprintw(winTransmission, 1, 2, mesg);
wgetnstr(winTransmission, command, sizeof command);
verifInput(command);
}