Malloc 字符数组。字符串

Malloc array of characters. String

提问人:Affectionate Mango 提问时间:1/14/2023 最后编辑:MureinikAffectionate Mango 更新时间:1/14/2023 访问量:86

问:

我知道由于 NULL 字符,为字符串分配内存分配需要 n+1。但是,问题是,如果您分配了 10 个字符但输入了 11 个字符的字符串怎么办?

#include <stdlib.h>
int main(){
    int n;
    char *str;
    printf("How long is your string? ");
    scanf("%d", &n);
    str = malloc(n+1);
    if (str == NULL) printf("Uh oh.\n");
    scanf("%s", str);
    printf("Your string is: %s\n", str);
}

我尝试运行该程序,但结果仍然与 n+1 相同。

c 字符串 char malloc

评论

1赞 Ted Lyngmo 1/14/2023
“如果您分配了 10 个字符但输入了 11 个字符的字符串”,则您的行为未定义,因此请不要让这种情况发生。你不能相信这样的程序所做的任何事情。
1赞 abelenky 1/14/2023
程序询问你打算输入多长的字符串,你撒谎,告诉程序你只输入 10 个字符,但你实际上输入了 11 个字符。这是未定义的行为。任何事情都可能发生。由于体系结构原因,最常见的结果是程序似乎可以正常工作,即使无法保证其行为。
0赞 chux - Reinstate Monica 1/14/2023
命名法:“......--> 是 NULL 指针常量,最好在指针上下文中使用。这里最好的是 null 字符,因为它与 C 规范描述它的方式相匹配。NULL

答:

1赞 Mureinik 1/14/2023 #1

如果您分配了 10 个字符,但向其写入了 11 个字符,则您正在写入尚未分配的内存。这具有未定义的行为 - 它可能碰巧起作用,它可能会因分段错误而崩溃,并且它可能会执行完全不同的操作。简而言之 - 不要依赖它。char*

0赞 Lught 1/14/2023 #2

将 11 个字节写入 10 字节缓冲区时,最后一个字节将越界。根据多种因素,程序可能会崩溃,出现意外和奇怪的行为,或者可能运行良好(即您所看到的)。换言之,行为是未定义的。你几乎总是想避免这种情况,因为它是不安全和不可预测的。

尝试将更大的字符串写入 10 字节缓冲区,例如 20 字节或 30 字节。你会看到问题开始出现。

评论

0赞 user253751 1/14/2023
如果你写了 5000 字节,你几乎肯定会遇到问题。覆盖的字节越多,覆盖重要字节的可能性就越大。
0赞 Ted Lyngmo 1/14/2023
“根据几个因素,程序可能会崩溃,出现意外和奇怪的行为,或者可能运行良好(即你所看到的)。- 这样的程序UB。时期。仅仅通过在屏幕上看到预期的输出来确定“它运行良好”也非常困难。它还可以在后台重新格式化硬盘。
0赞 Eugene Sh. 1/14/2023
@user253751 或者会击中一些未映射的地址......
0赞 Lught 1/14/2023
@TedLyngmo “这样的程序有UB。句号“这正是我说的:”换句话说,行为是不确定的。
0赞 Ted Lyngmo 1/14/2023
“该计划可能 [...]有意想不到的......“是我反对的。最好说清楚。该程序具有未定义的行为,几乎可以执行任何操作。
1赞 O. Jones 1/14/2023 #3

如果超出 malloc 提供的内存区域,则会损坏 RAM 堆。如果幸运的话,你的程序会立即崩溃,或者当你释放内存时,或者当你的程序在你覆盖的区域之后使用内存块时。当你的程序崩溃时,你会注意到这个错误,并有机会修复它。

如果你运气不好,你的代码就会投入生产,一些网络犯罪分子会想出如何利用你的内存溢出来诱骗你的程序运行一些恶意代码或使用他们提供给你的一些恶意数据。如果你真的不走运,你会在克雷布斯安全或其他一些信息安全新闻媒体上得到报道。

别这样。如果你对自己避免这样做的能力没有信心,就不要使用 C。请改用具有本机字符串数据类型的语言。认真地。

1赞 chux - Reinstate Monica 1/14/2023 #4

如果您分配了 10 个字符但输入了 11 个字符的字符串怎么办?

scanf("%s", str);经历未定义的行为 (UB)。任何事情都可能发生,包括“我尝试运行程序,但结果仍然与 n+1 相同”,将显示为正常。

相反,始终使用 width with 和 一旦已满就停止读取。例:scanf()"%s"str[]

char str[10+1];
scanf("%10s", str);

由于此处是可变的,因此请考虑改用 to 读取一行输入。nfgets()

请注意,还会读取并保存尾随 .
最好用于用户输入并完全放弃呼叫,直到您了解为什么不好。
fgets()'\n'fgets()scanf()scanf()

str = malloc(n+1);
if (str == NULL) printf("Uh oh.\n");
if (fgets(str, n+1, stdin)) {
  str[strcspn(str, "\n")] = 0; // Lop off potential trailing \n

评论

0赞 Ted Lyngmo 1/14/2023
strchr 可能会派上用场而不是强硬strcspn
0赞 chux - Reinstate Monica 1/14/2023
@TedLyngmo更有可能使用错误。你建议如何使用它?strchr()
0赞 Ted Lyngmo 1/14/2023
我怀疑这是一个技巧问题:-) 要找到它,请取消引用指针,将”strchr\0'
0赞 chux - Reinstate Monica 1/14/2023
@TedLyngmo 由于缓冲区已满,最后一行缺少或读取空字符,因此未经测试的指针带有“取消引用指针,分配'\0'”的指针可能会遇到麻烦。strchr(str, '\n')NULLfgets()'\n'
1赞 chux - Reinstate Monica 1/14/2023
@Ted 不,更像是 kärlek förlorad