【问题标题】:strcat makes crash program (0xc0000005)strcat 制作崩溃程序 (0xc0000005)
【发布时间】:2014-12-19 12:15:20
【问题描述】:

我需要画一行我想要的字符。所以我为此编写了一个函数:

void fDrawLine(int length)
{
    int i;
    char * compLine = (char *) malloc(WINDOW_WIDTH + 2);

    for(i = 0; i < length; i++)
        strcat(compLine, "-");

    fDrawSpacedMessage(compLine, -1, TRUE);
}

WINDOW_WIDTH 定义为80fDrawSpacedMessage 是另一个打印文本居中等功能。

它正在完美构建,没有错误,没有警告。但在运行时,一切正常,但如果fDrawLine 执行,程序崩溃并给出错误代码0xc0000005。我知道这是关于内存分配的,但我已经初始化了 compLine 字符串。

我已经尝试了几件事;我认为是另一个功能导致了它,所以我隔离了fDrawLine,但崩溃仍在继续。使用compLine[0] = 0;compLine[WINDOW_WIDTH] = {0}; 更改初始化没有帮助。

它在我的另一台机器上运行良好,它运行 Ubuntu,使用最新的 gcc,但是在 Windows 上使用 Code::Blocks (MinGW) 时,它总是崩溃。

这段代码有什么问题?

【问题讨论】:

  • 为什么不使用memset 填充'-'?还有length的价值是什么?
  • 由于这是一个学校项目,您大概是在学习编码。除了其他事情,看看你的函数然后回答这个问题:调用fDrawLine(WINDOW_WIDTH*2);实际上会做什么?学习防御性编程
  • 1) 需要确保length 不会太大。添加assert(length &lt; (WINDOW_WIDTH + 1)); 2) 2 在这里是一个神奇的数字。提供有关 2 的详细信息? (fDrawSpacedMessage() 会不会尝试显示 81 长的“---...---”?)

标签: c string pointers for-loop strcat


【解决方案1】:

分配的内存开始包含垃圾。将其设置为空字符串,例如这样:

compLine[0] = '\0';

【讨论】:

  • 他说这没有帮助。
  • 很可能还有其他错误。由于我们还没有看到一个完整但最小的例子仍然能说明问题,所以很难说。
【解决方案2】:

不要将compLine 声明为指针,因为您不需要它,而且实际上您的函数中有内存泄漏,首先以这种方式声明compLine

char compLine[1 + WINDOW_WIDTH] = {0}; // strings need an extra byte at the end to mark the end.

然后使用memset 像这样设置'-' 字符

memset(compLine, '-', length);

当然,检查length &lt;= WINDOW_WIDTH

这是你的固定功能,你可以试试

void fDrawLine(int length)
{
    char compLine[1 + WINDOW_WIDTH] = {0}; // initialized so that last byte is '\0'.
    if (length > WINDOW_WIDTH)
        length = WINDOW_WIDTH;
    memset(compLine, '-', length);        
    fDrawSpacedMessage(compLine, -1, TRUE);
}

除了使用strcat 那样是个坏主意,你可以这样做

char *compLine = malloc(1 + length); // the last extra '\0' byte.
if (compLine == NULL) // malloc returns NULL on failure to allocate memory
    return; // so we must abort this function in that case.
for(i = 0; i < length; i++)
    compLine[i] = '-';
compLine[length] = '\0';

fDrawSpacedMessage(compLine, -1, TRUE);
free(compLine);

在这种情况下你也可以使用memset,实际上更好。

【讨论】:

  • 这里并没有太大的性能差异,但是在第一个示例中最好手动将compLine[length]设置为\0,而不是将整个数组初始化为0s。
  • 也许吧,但是对于新程序员来说,这样初始化是一个好习惯,因为他们经常忘记终止'\0',这是迄今为止我见过的最常见的错误。我当然可能是错的。有些人甚至可能习惯于calloc 来避免这个问题。
  • 如果他们忘记了终止 '\0' 他们将忘记初始化整个数组。令人惊讶的是,有多少开发人员在将大缓冲区加载到下一行之前将它们浪费在初始化大缓冲区上。
【解决方案3】:

下面的代码存在一些问题

void fDrawLine(int length)
{
    int i;
    char * compLine = (char *) malloc(WINDOW_WIDTH + 2);

    for(i = 0; i < length; i++)
        strcat(compLine, "-");

    fDrawSpacedMessage(compLine, -1, TRUE);
}

首先,length 参数至少应为unsigned int,因为负长度没有意义。理想情况下,您应该使用size_ti 也是如此。

接下来,您并没有保护自己免受 length 的无效值的影响。隐含的契约是 0 length WINDOW_WIDTH - 让它显式化。

您使用动态分配的内存会导致内存泄漏,因为您在调用fDrawSpacedMessage() 后没有释放它。

最后,strcat 附加单个字符是多余的。

将所有这些放在一起,这是一个替代实现。

void fDrawLine(size_t length)
{
    size_t actual_length = length <= WINDOW_WIDTH ? length : WINDOW_WIDTH;
    char compLine[WINDOW_WIDTH+2];

    memset(compLine, '-', actual_length);
    compline[actual_length] = '\0';
    fDrawSpacedMessage(compLine, -1, TRUE);
}

我在WINDOW_WIDTH+2 留下了compline,因为我猜fDrawSpacedMessage 添加了一个换行符。

如果还是崩溃,问题出在fDrawSpacedMessage

【讨论】:

    猜你喜欢
    • 2012-08-30
    • 1970-01-01
    • 2015-09-22
    • 2013-06-22
    • 1970-01-01
    • 1970-01-01
    • 2016-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多