C - 通过strcpy打印char *是否相互矛盾?

时间:2017-09-27 23:56:03

标签: c pointers reference char

首先发布这里,我已经使用过这个网站多年了,但这种困境真的很烦人。因此,当我使用C编译器通过VS2015 Developer Command提示符运行此C代码时:

#include <stdio.h>
#include <string.h>

int main(){
   char* ptr = NULL;
   const char* pt2 = "hello";
   strcpy(&ptr, pt2);
   printf("%s",&ptr);
   return 0;
}

我收到了这些警告:

midterm_c.c(35): warning C4047: 'function': 'char *' differs in levels of indirection from 'char **'
midterm_c.c(35): warning C4024: 'strcpy': different types for formal and actual parameter 1
midterm_c.c(36): warning C4477: 'printf' : format string '%s' requires an argument of type 'char *', but variadic argument 1 has type 'char **'

然而,当我运行它时,它打印“hello”,这不应该发生,因为在ptr变量上使用引用运算符是没有意义的。但是当我在没有它们的情况下运行此代码时:

char* ptr = NULL;
const char* ptr2 = "hello";
strcpy(ptr, ptr2);
printf("%s",ptr);
return 0;

我没有收到警告,成功编译,但是当我运行它时程序崩溃,即使这应该正常工作。我真的很沮丧,因为这对我没有任何意义,也是我现在真的很讨厌C的原因之一。如果有人知道这是怎么回事,我真的很感激。谢谢。

4 个答案:

答案 0 :(得分:3)

在您的工作代码中,您基本上只是将堆栈的一部分视为字符串缓冲区;标准是公然违法的,但它恰好起作用,因为你不会读取你在st脚之后踩踏的任何东西。

char**传递给strcpy没有任何意义,这是正确的,但最终发生的事情是它写入char*变量本身(以及一些相邻的内存,如果它是32位程序),将其视为char的数组(毕竟,8字节指针有足够的空间容纳7个字符的字符串和NUL终结符)。实际上,您的代码是错误的代码,仍然会像正确的代码一样,因为:

char* ptr = NULL;
const char* pt2 = "hello";
strcpy(&ptr, pt2);
printf("%s",&ptr);

编译成几乎完全像这样的代码(除了警告):

char ptr[sizeof(char*)];  // Your char* behaves like an array
const char* pt2 = "hello";
strcpy(ptr, pt2);
printf("%s", ptr);

如果您不使用ptr的地址,则会将NULL指针传递给strcpy,该指针会立即崩溃(因为您无法写入NULL几乎所有系统上都有指针的目标。)

当然,正确的解决方案是使ptr指向已分配的内存,可以是全局,自动或动态分配的内存。例如,使用堆栈缓冲区,这是合法的:

char buf[8];

char *ptr = buf; // = &buf[0]; would be equivalent
const char* pt2 = "hello";
strcpy(ptr, pt2);
printf("%s", ptr);

虽然这样做毫无意义,但ptr可以在任何地方替换为buf并删除ptr

char buf[8];
const char* pt2 = "hello";
strcpy(buf, pt2);
printf("%s", buf);

答案 1 :(得分:1)

首先,您不知道如何使用strcpy。第一个参数需要指向可用于复制的空间,它不会为您分配空间。

你的第一个例子可能只是“有效”,因为它正在复制到堆栈空间。这是未定义的行为,会导致各种问题。

您的第二个示例(更正确的一个)通常会导致段错误,因为您试图复制到(或读取)空地址。

答案 2 :(得分:0)

您需要为ptr变量(malloc)分配内存。然后,有用的函数是strdup()。
它需要一个字符串,为新字符串分配好的内存空间,并在返回新字符串之前复制源内容。
你可以这样做:

ptr = strdup(pt2);

文档:http://manpagesfr.free.fr/man/man3/strdup.3.html

答案 3 :(得分:0)

您正在写入随机内存,这是未定义的行为。这意味着根据C标准,允许编译器生成实际上可以执行任何操作的代码,包括但不限于:

  1. 打印“你好”。

  2. 打印随机乱码。

  3. 崩溃。

  4. 破坏应用中的其他变量。

  5. 在时空织物上撕开一个洞,造成第五维邪恶空间狐猴的入侵,破坏了Kopi Luwak咖啡的市场,导致供应过剩。

  6. Tl;博士:不要这样做。