C-"Run-Time Check Failure #2 - Stack around the variable 'cstringValue' was corrupted."

C - "Run-Time Check Failure #2 - Stack around the variable 'cstringValue' was corrupted."

这段代码是检查用户输入的长度是否在下限和上限范围内。或者如果上限和下限相等,测试字符串长度是否等于变量'equal'。现在,我正在尝试 return 字符串 STEVEN 到主函数,但它继续弹出“运行-Time Check Failure #2 - Stack around the variable 'cstringValue' was corrupted. “当长度数不等于变量 'equal'.

时,代码工作正常

我试过以下方法:

函数代码:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include "core.h"
#include <string.h>
void inputCString(char *charPointer[], int lower, int upper)
    {
        int count, equal;
        
        
        if (upper != lower)
        {
            
            goto notEqual;
            
        }
        else if (upper == lower)
        {
            goto upperEqualLower;
        }
        notEqual:
            do
            {
                scanf("%s%n", *charPointer, &count);
                count--;
                if (count > upper || count < lower)
                {
                    printf("ERROR: String length must be between %d and %d chars: ", lower, upper);
                }
                else
                {
                    
                    return *charPointer;
                }

            } while (count > upper || count < lower);
        
    upperEqualLower:
        do
        {
            equal = upper;
            
            scanf("%s%n", &*charPointer, &count);
            count--;
            
            if (count != equal)
            {
                printf("ERROR: String length must be exactly %d chars: ", upper);
            }
            else if (count == equal)
            { 
                
                return *charPointer;
            } 
        } while (count != equal);
        

主要:


    char cstringValue[7] = { '[=12=]' };

    
    printf("TEST #6: - Instructions:\n"
        "1) Enter the word 'horse'   [ENTER]\n"  // too short
        "2) Enter the word 'chicken' [ENTER]\n"  // too long
        "3) Enter the word 'STEVEN'  [ENTER]\n"  // just right
        ":>");

    
    inputCString(cstringValue, 6, 6);

    printf("////////////////////////////////////////\n");
    printf("TEST #6 RESULT: ");
    printf("%s (expected result: STEVEN)\n", cstringValue);
    printf("////////////////////////////////////////\n\n");

提前致谢。

您的 charPointer 参数的类型是 char** – 虽然您对第一个 scanf(不等式)正确取消引用,但对第二个(不等式)不这样做案例:&*somePointer 等同于 somePointer)。这是未定义的行为,因为指针类型不符合格式说明符。

此外,您需要创建一个指向要传递给函数的 cstringValue 指针的指针——简单地执行 &cstringValue 将提供一个指向数组的指针,这也是错误类型。所以你需要:char* ptr = cstringValue; inputCString(&ptr, ...);。编译器应该警告你指针类型不匹配(如果没有,提高警告级别!),你 绝对 应该听! (在相等的情况下,你可能会逃脱,因为你提供了两次不匹配的指针,并且错误可能会相互补偿——仍然是未定义的行为,工作代码是纯属运气).

不过,更简单的是,只需将参数转换为普通的 char* 指针,然后就可以直接将其传递给 scanf,而无需像现在这样取消引用并将输入数组传递给函数也再次正确。

根据您的输入,您也可以通过超出数组边界写入来冒未定义行为的风险 – 考虑像“dragonfly”这样的输入,它不适合数组! scanf 仍然会尝试写入,因为您不限制输入长度 – 长度检查 (count) 仅在 数据已写入后发生到阵列!

提供更长的缓冲区可以降低风险,但不能消除风险。为了安全起见,您需要将 scanf 限制为仅扫描到某个最大值。不幸的是,不能像 printf 那样通过向 scanf 传递附加参数来提供最大值,因此您需要相应地调整格式字符串,或者使用常量字符串:

#define MAX_INPUT 7
#define ARRAY_SIZE (MAX_INPUT + 1) // need space for a null-terminator!
#S(TEXT) S_(TEXT)                  // stringifying macro
#S_(TEXT) #TEXT                    // need indirection for

scanf("%" S(MAX_INPUT) "s", ...);

// quite a lot of work to be safe, I know...

或动态:

char format[8];
sprintf(format, "%%%ds%%n", length - 1);
// - 1: need to leave space for the null terminator
// (assuming you provide length as an additional parameter)

scanf(format, ...);

您的代码中还有很多其他问题:

你尝试return *charPointer;,但是return函数的类型是void

if(condition) {} else if(complementary condition) { }——如果不满足初始条件,那么补充条件必须——所以如果进入else分支,第二个if 总是会遇到,你应该放弃它:if(condition) {} else {}.

goto 的有效用例(比如退出嵌套循环),但这里不是。您可以将相应的代码块放入 ifelse 分支的主体中。此外,您根本不必区分 lowerupper 之间的差异,就好像这两个值等于 count < lowercount > upper 中的一个一样 如果 count 不等于其中任何一个(它们是相等的,还记得吗?),则适用。嗯,错误信息不同,但你可以在循环之前 select 它:`char const* errorMsg = upper == lower ? “恰好”:“介于;”。

更有趣的是对 lower <= upper 进行额外检查,如果没有,则结合适当的错误处理,因为这肯定会导致无限循环。

count-- – 你为什么要减少它? "%n"提供字符数read,not字符数written给数组(后者包含一个null-terminator,前者不包含)。因此,如果为 "abc" 读取了 3 个字符,您最终会得到 2 个字符,我怀疑这是否是您真正想要的...

标签不产生任何范围——它们只是一个标记,在 goto 的情况下继续执行,但在其他情况下将被忽略。这意味着如果您在 notEqual 之后完成代码,它将继续执行 upperEqualLower 之后的代码。如果您知道这一点,我似乎不清楚,所以请注意 - 在您的 特定 情况下, fall-through 在到达之前被 returning 从函数中阻止下一个标签,所以这里不是问题。不过,如果您遵循上面 goto 的建议,您根本不会 运行 进入这个(进入 if/else 块)。

你的循环不需要检查任何条件:你检查已经在内部的完全相同的条件并通过returning打破循环,所以如果达到在循环体的结尾,条件 为真,您仍然可以继续。您可以简单地使用 for(;;) 循环。

解决所有这些问题您的代码如下所示:

void inputCString(char charPointer[], size_t length, size_t lower, size_t upper)
// size_t: correct type for specifying array or object sizes; aditionally
// it's unsigned, as negative values for lower and upper are meaningless anyway
{
    if(upper < lower)
    {
        // error handling!
    }

    char const* errorMsg = lower == upper ? "exactly" : "in between"; // examples

    char format[8];
    sprintf(format, "%%%ds%%n", length - 1);
    int count;
    for(;;)
    {
        scanf(format, charPointer, &count);
        // personal preference of mine: place the return into the if block
        // -> invert condition
        if (lower <= count && count <= upper)
        {
            return;
        }

        // surplus argument in case of equality is no problem:
        printf(errorMsg, lower, upper);
    }
}