【问题标题】:Analysis on character pointer with dynamic memory allocation动态内存分配的字符指针分析
【发布时间】:2015-09-12 14:41:33
【问题描述】:

我已经用C编写了以下代码。我需要了解字符指针通过malloc()动态分配内存后如何执行字符串复制操作。

我的代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUFFSZ 20
int main()
{
        char *name = NULL;
        char my_name[BUFFSZ] ;
        memset(my_name,0,BUFFSZ);
        strcpy(my_name,  "vinothkumarsaradavallivaradathirupathi");
        printf("string copied is %s\n",my_name);
        if ((name = malloc(1 + strlen(my_name)+1)) != NULL)
                strcpy(name,my_name);
        printf("Name is %s\n",name);
        free(name);
        name = NULL;
        return 0;
}

实际输出:

string copied is vinothkumarsaradavallivaradathirupathi
Name is vinothkumarsaradavalliva��

根据代码,我期待下面的输出,但上面只有一个。如果有人清楚地解释这一点会很有帮助。

预期输出:

string copied is vinothkumarsaradaval
Name is vinothkumarsaradaval

当我在 GDB 中运行这段代码时,我得到了以下输出:

Breakpoint 2, main () at first_pgm.c:12
12              memset(my_name,0,BUFFSZ);
(gdb) n
14              strcpy(my_name,  "vinothkumarsaradavallivaradathirupathi");
(gdb) p name
$1 = 0x0
(gdb) p my_name
$2 = '\000' <repeats 19 times>
(gdb) n

Breakpoint 3, main () at first_pgm.c:15
15              printf("string copied is %s\n",my_name);
(gdb) p my_name
$3 = "vinothkumarsaradaval"
(gdb) n
string copied is vinothkumarsaradavallivaradathirupathi

这里,为什么“$3”和“复制的字符串”输出是冲突的?

【问题讨论】:

  • 你知道你正在将 39 个字节复制到一个只有 20 个元素的数组中吗?
  • 是的,我故意编程来理解内存管理
  • 为什么这会帮助您理解内存管理?这只会导致不确定的行为,因此它不会保持一致,因此对学习目的没有用。

标签: c string pointers dynamic-memory-allocation strcpy


【解决方案1】:

预期输出

等等。此代码不能有预期输出。此代码生成undefined behavior

在您的代码中

 strcpy(my_name,  "vinothkumarsaradavallivaradathirupathi")

您超出了分配的内存。在您的情况下,my_name 没有足够的内存来保存源字符串文字的完整内容。

结果:未定义的行为。

请为目标缓冲区分配足够的内存,以便它可以保存源字符串和空终止符。

也就是说,

  1. Do not castmalloc()和family的返回值。

  2. 当您不打算使用任何命令行参数时,推荐的(而是必需的main() 签名是int main(void)

【讨论】:

  • 其实是required签名,不只是推荐。
  • @Olaf 我用 "recommended""implementation-defined way" 部分留出了空间。希望我没有被误解。 :-)
  • 好吧,对于托管环境,实际上已经没有空间了。对于独立式,根本没有推荐。所以:我很欣赏你对绝对陈述的谨慎,但这一次:去做吧,勇敢点! ;-))
  • 好的,我知道了。我解释说,基础仍然必须是int main(...)。所以返回类型不可更改,但允许使用int 的别名。 “实现定义的方式”适用于参数 (imo 主要适用于实际调用main() 的启动代码如何构造它们)。
  • @Olaf :-)。好的,我今天请假。现在是凌晨 2:00 (IST)。明天见。 :-)
【解决方案2】:

您复制的字节数超出了允许的范围,这会导致未定义的行为。因为您的数组只能存储 20 个字符,但您要复制 39 个字符。

只是改变

#define BUFSIZE 39

它会起作用的。

还有,这个

if (NULL != (name = (char *)malloc(sizeof(char)*(strlen(my_name)+1))))

非常丑,

  1. 不要强制转换malloc() 的返回值void *,它会在不强制转换的情况下转换为任何其他指针类型。
  2. 不要使用 sizeof(char),因为它的定义是 1。

修复看起来像的代码

if ((name = malloc(1 + strlen(my_name))) != NULL)

然后你检查NULL,但你仍然这样做

printf("Name is %s\n", name)

如果name == NULL,这将导致不确定的行为。

【讨论】:

  • 有用的,一如既往,+1。 :-)
  • 第 2 点和第 3 点有可靠的技术依据,但尤达条件是见仁见智的问题。我不喜欢他们,但是用这些绝对的术语表达意见可能会使人们不太可能听从你的其他建议(这很好,顺便说一句)。
  • 删除了 yoda 条件并根据您的指南更改了代码。
  • != NULL 无论如何都是多余的
  • @MattMcNabb 你是对的,它继续printf()它。
【解决方案3】:

这是典型的缓冲区溢出。 strcpy 不会停止将字符写入其目标缓冲区,直到找到终止 '\0' 字符。它正在写入的内存是实现定义的,这就是为什么您不能可靠地将其读回的原因。使用strncpy 设置strcpy 将复制的数据量上限。

【讨论】:

  • 是的,我明白你的意思。但是当我运行 GDB 时,我得到了类似下面的东西
  • 断点 2,main () at first_pgm.c:12 12 memset(my_name,0,BUFFSZ); (gdb) n 14 strcpy(my_name, "vinothkumarsaradavallivaradathirupathi"); (gdb) p name $1 = 0x0 (gdb) p my_name $2 = '\000' (gdb) n 断点 3, main () at first_pgm.c:15 15 printf("复制的字符串是 %s\ n",我的名字); (gdb) p my_name $3 = "vinothkumarsaradaval"
  • 调试器知道只有 20 个字符是变量 my_name 的一部分,因此无论 strcpy 写了多少个字符,它都只会显示那么多。
猜你喜欢
  • 2019-07-12
  • 2015-02-05
  • 2013-06-07
  • 2014-06-19
  • 1970-01-01
  • 1970-01-01
  • 2019-06-24
  • 2013-10-04
  • 1970-01-01
相关资源
最近更新 更多