我的程序在不同的机器上给出不同的输出

My program is giving different output on different machines..!

本文关键字:输出 机器 程序 我的      更新时间:2023-10-16
#include<iostream>
#include<string.h>
#include<stdio.h>

int main()
{
    char left[4];
    for(int i=0; i<4; i++)
    {
        left[i]='0';
    }
    char str[10];
    gets(str);
    strcat(left,str);
    puts(left);
    return 0;
}

对于任何输入,它都应该将 0000 与该字符串连接起来,但在一台 PC 上,它在"0000"和输入字符串之间显示菱形符号...!

将可能的九个(或更多,gets没有边界检查(字符串附加到三个字符串(包含四个字符,没有字符串终止符(。完全没有字符串终止。因此,当您使用 puts 打印时,它将继续打印,直到找到字符串终止字符,该字符可能位于内存中的任何位置。简而言之,这是缓冲区溢出的教科书示例,缓冲区溢出通常会导致您所看到的未定义的行为

在 C 和 C++ 中,必须终止所有 C 样式字符串。它们由特殊字符终止:''(或纯 ASCII 零(。还需要在strcat调用中为目标字符串提供足够的空间。


适当的工作计划:

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(void)
{
    /* Size is 4 + 10 + 1, the last +1 for the string terminator */
    char left[15] = "0000";
    /* The initialization above sets the four first characters to '0'
     * and properly terminates it by adding the (invisible) '' terminator
     * which is included in the literal string.
     */
    /* Space for ten characters, plus terminator */
    char str[11];
    /* Read string from user, with bounds-checking.
     * Also check that something was truly read, as `fgets` returns
     * `NULL` on error or other failure to read.
     */
    if (fgets(str, sizeof(str), stdin) == NULL)
    {
        /* There might be an error */
        if (ferror(stdin))
            printf("Error reading input: %sn", strerror(errno));
        return 1;
    }
    /* Unfortunately `fgets` may leave the newline in the input string
     * so we have to remove it.
     * This is done by changing the newline to the string terminator.
     *
     * First check that the newline really is there though. This is done
     * by first making sure there is something in the string (using `strlen`)
     * and then to check if the last character is a newline. The use of `-1`
     * is because strings like arrays starts their indexing at zero.
     */
    if (strlen(str) > 0 && str[strlen(str) - 1] == 'n')
        str[strlen(str) - 1] = '';
    /* Here we know that `left` is currently four characters, and that `str` 
     * is at most ten characters (not including zero terminaton). Since the
     * total length allocated for `left` is 15, we know that there is enough
     * space in `left` to have `str` added to it.
     */
    strcat(left, str);
    /* Print the string */
    printf("%sn", left);
    return 0;
}

代码中有两个问题。

首先,left不是以 nul 结尾终止的,因此strcat最终会在数组末尾之外查找附加字符的适当位置。在数组的末尾放一个''

其次,left不够大,无法容纳调用strcat的结果。必须有足够的空间来容纳生成的字符串,包括 NUL 终止符。因此,left的大小应至少为 4 + 9,以允许left开头的三个字符(加上 nul 终止符(和来自str的 9 个字符(假设gets没有导致溢出(。

这些错误中的每一个都会导致未定义的行为,这解释了不同平台上的不同结果。

我不知道

你为什么要费心包含<iostream>,因为你没有在代码中使用任何C++功能。 如果您有以下条件,您的整个程序会短得多:

#include <iostream>
#include <string>
int main()
{
    std::string line;
    std::cin >> line;
    std::cout << "You entered:  " << line;
    return 0;
}

由于std::string将以空值终止,因此没有理由强制其以 4 空终止。

问题 #1 - 不是合法字符串:

char left[4];
for(int i=0; i<4; i++)
{
    left[i]='0';
}

字符串必须以零字符结尾,''不能'0'。这会导致您所描述的内容。

问题 #2 - fgets .您可以在一个小缓冲区上使用它。非常危险。

问题 #3 - strcat .再次尝试用额外的字符串填充一个应该已经填满的超小缓冲区。

此代码看起来像是缓冲区溢出攻击的邀请。

在 C 中,我们所说的字符串是一个以 null 结尾的字符数组。string.h 库中的所有函数都基于字符数组末尾的此 null。你的字符数组不是以null结尾的,因此不是字符串,所以这里不能使用字符串库函数strcat。