在 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()oldtextinwindow - 这也是分配的内存 - 被扔掉了。那肯定是内存泄漏。

最后,一个微妙的问题。由于 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);
}