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
的有效用例(比如退出嵌套循环),但这里不是。您可以将相应的代码块放入 if
和 else
分支的主体中。此外,您根本不必区分 lower
和 upper
之间的差异,就好像这两个值等于 count < lower
或 count > 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);
}
}
这段代码是检查用户输入的长度是否在下限和上限范围内。或者如果上限和下限相等,测试字符串长度是否等于变量'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
的有效用例(比如退出嵌套循环),但这里不是。您可以将相应的代码块放入 if
和 else
分支的主体中。此外,您根本不必区分 lower
和 upper
之间的差异,就好像这两个值等于 count < lower
或 count > 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);
}
}