C语言中使用ncurses函数时的分段错误

C语言中使用ncurses函数时的分段错误,c,codeblocks,ncurses,C,Codeblocks,Ncurses,首先,我用ncurses创建了两个窗口:一个用于传输,一个用于接收。基本上,一个用来写命令,另一个用来打印命令。为了在接收窗口中写入输入,我做了一个小函数来连接接收窗口中已经存在的字符串和用户编写的字符串(我认为问题就在这里) 因此,当我运行代码时,程序失败,并在wrefresh(WinReceivement)行显示转储的分段故障代码 但奇怪的是,如果输入是7个字符或更少,它就可以工作,如果输入是8个或更多,它就会中断 我正在使用代码::块 截图如下: 下面是一些代码: //Global var

首先,我用ncurses创建了两个窗口:一个用于传输,一个用于接收。基本上,一个用来写命令,另一个用来打印命令。为了在接收窗口中写入输入,我做了一个小函数来连接接收窗口中已经存在的字符串和用户编写的字符串(我认为问题就在这里)

因此,当我运行代码时,程序失败,并在
wrefresh(WinReceivement)行显示转储的分段故障代码

但奇怪的是,如果输入是7个字符或更少,它就可以工作,如果输入是8个或更多,它就会中断

我正在使用代码::块 截图如下:

下面是一些代码:

//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()
的使用完全不正确,因为它接受用户的输入并将其填充到缓冲区中,但您尚未分配缓冲区。我们不知道
命令的值是多少,所以它将数据存储到随机内存中

解决此问题的错误方法是:

char command[256];
wgetstr(winTransmission, command); // NO
因为虽然您会提供一个存储用户输入的位置,
wgetstr()
不知道缓冲区有多大,如果用户输入太多,它也会覆盖那里的内存。不太好

相反,我们将使用一个有界版本
wgetnstr()
,该版本需要一个缓冲区和一个计数

现在它将永远不会覆盖缓冲区

其他问题:尽管在代码末尾释放了
textinwindow
内存,但每次调用
concat()
时,
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);
}
#包括
#包括
#包括
#包括
//全局变量
窗口*接收;
窗口*winTransmission;
char命令[256];
const char mesg[]=“输入命令”;
//变量将输入存储在接收窗口中
char*textinwindow=0;
无效验证输入(常量字符*cmd);
//主要
int main(int argc,char*argv[])
{
initscr();
/*窗口接待*/
WinReceivement=newwin(15,0,0,0);
wrefresh(Winreceipt);
/*窗口传输*/
winTransmission=newwin(8,0,15,0);
wrefresh(winTransmission);
mvwprintw(winTransmission,1、2、mesg);
wgetnstr(winTransmission,command,sizeof command);
验证输入(命令);
免费(文本窗口);
出口(0);
}
//concat函数(我认为错误在哪里)
字符*concat(常量字符*s1,常量字符*s2)
{
//2=换行符+空格
//1=最终NUL字节
char*result=(char*)malloc(strlen(s1)+2+strlen(s2)+1);
strcpy(结果,s1);
strcat(结果“\n”);
strcat(结果,s2);
返回结果;
}
//验证输入(程序失败时)
无效验证输入(常量字符*cmd)
{
//释放除第一次外的旧内存
如果(textinwindow==0)
textinwindow=concat(“,cmd);
其他的
{
char*save=textinwindow;
textinwindow=concat(textinwindow,cmd);
免费(节省);
}
/*窗口接待*/
mvwprintw(winReception,1,2,“%s”,textinwindow);
wrefresh(Winreceipt);
/*窗口传输*/
touchwin(winTransmission);
wclear(winTransmission);
wrefresh(winTransmission);//程序在此失败
mvwprintw(winTransmission,1、2、mesg);
wgetnstr(winTransmission,command,sizeof command);
验证输入(命令);
}

concat()函数中,代码没有分配足够的内存。它需要两个字符串的大小(您可以这样做),加上结尾的NUL字节的一个大小(您可以这样做),但是
“\n”
字符还需要两个大小。写入超过分配数组的结尾,可能会导致问题。还建议将
void verifInput(char*cmd)放入位于上方
main
的顶部,以便代码看到正确的原型。你有没有试过打开max编译器警告,看看这是否给了你任何提示?@SteveFriedl我尝试了你提到的所有东西,但仍然给了我同样的错误。但是,我不知道如何打开max compiler warnings.Aha。
wgetstr()
调用可能是罪魁祸首。您将指针的地址传递给缓冲区(而不是缓冲区本身),但这是随机内存。我很惊讶它并没有就此消亡。@SteveFriedl而不是
wgetstr(winTransmission,&command)我应该有
wgetstr(winTransmission,command)?我还制作了一些函数参数
const char*
,而不是仅仅
char*
,以表示函数希望永远不会写入它们。这并不是绝对必要的,但这是一个很好的习惯去习惯const-Aware。哇,它工作得很好。非常感谢!现在回到编码。似乎我应该多关注一下
%
问题:将用户输入传递给任何接受printf样式格式列表的内容都会带来安全风险。
#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);
}