繁体   English   中英

C-通过strcpy打印char *是矛盾的吗?

[英]C - printing a char* through strcpy is acting contradictory?

我在这里的第一篇文章已经使用了多年,但是这个难题实在令人讨厌。 因此,当我使用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的原因之一。 如果有人知道这是怎么发生的,我将非常感激。 谢谢。

在您的工作代码中,您基本上只是将堆栈的一部分视为字符串缓冲区。 按照标准,这显然是非法的,但它确实起作用,因为您在踩踏后不会从踩踏的东西中读取任何内容。

您是正确的,将char**传递给strcpy是没有意义的,但是最终发生的事情是,它会写入char*变量本身(如果是32位程序,还会写入一些相邻的内存),并将其视为一个数组char (毕竟,一个八字节的指针有足够的空间容纳七个字符串和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);

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

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

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

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

ptr = strdup(pt2);

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

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

  1. 打印“你好”。

  2. 打印随机乱码。

  3. 崩溃了

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

  5. 在时空的结构上打一个洞,导致来自第五维度的邪恶的空间狐猴的入侵,由于供应过剩而破坏了Kopi Luwak咖啡的市场。

Tl; dr:不要那样做。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM