理解 char *、char[] 和 strcpy()
Posted
技术标签:
【中文标题】理解 char *、char[] 和 strcpy()【英文标题】:Understanding char *, char[] and strcpy() 【发布时间】:2014-10-19 14:34:39 【问题描述】:我的理解如下:
char *
指向一个字符串常量,修改它指向的数据是未定义的。但是,您可以更改它指向的位置。
char[]
指的是可以更改的内存块。您可以更改其内容,但不能更改其引用的内容。
strcpy(dest, src)
将src
复制到dest
。
我的问题是,将strcpy()
与dest
一起使用是不正确的char *
已经指向某些东西(因为我相信旧内容将被@覆盖987654329@ - 这是未定义的行为)?
例如:
char *dest = malloc(5);
dest = "FIVE";
char *src = malloc(5);
src = "NEW!";
strcpy(dest, src); /* Invalid because chars at dest are getting overwritten? */
【问题讨论】:
char * points to a string constant
- 不。适当设置的char *
指向char
。无论是char
的序列是否适当地以nulchar 结尾,都是它处理的数据的产物。而且它不是恒定的。 array(在您的列表中:char[]
)的一般描述更接近现实。一个指针持有一个地址;一个数组是一个地址。
首先,char * 是一个指向 char 的指针。在 C 中,字符串是由零字符终止的字符序列,因此通常 char * 指向此类字符串的开头。但它也可以指向一个缓冲区的开始,该缓冲区旨在接受这样的字符串。如果字符串不是文字,可以修改。
@WhozCraig "数组是地址" - 呃,数组有个地址
数组不是地址;它们是由非零元素组成的对象
@user93353 我知道我的理解力很差,我是个初学者。学习 C 作为我的第一语言很难。
【参考方案1】:
很遗憾,您的理解并不完全正确。
char *
指向字符数据,由于其中没有const
,因此您可以写入指向的数据。
但是,完全可以这样做:
char *a = "hello";
它为您提供了一个指向只读数据的读/写指针,因为字符串文字存储在只读内存中,但语言的语法并不“认为”为常量。
上面最好写成:
const char *a = "hello";
为了更清楚地说明您不能修改a
指向的数据。
另外,您将malloc()
和分配混合的示例是错误的。
这个:
char *dest = malloc(5);
dest = "FIVE"; /* BAD CODE */
是糟糕的代码,你不应该这样做。它只是用指向字符串"FIVE"
的指针覆盖dest
返回的指针,该字符串作为字符串文字存在于(同样是只读的)内存中的某处。
用字符串数据初始化新分配的内存的正确方法是使用strcpy()
:
char *dest = malloc(5);
if(dest != NULL)
strcpy(dest, "five");
请注意,检查malloc()
的返回值是个好主意。
对同一个内存进行多次写入是没有问题的,这是 C 语言中一个非常基本的想法;变量代表内存,可以通过“覆盖”在不同时间赋予不同的值。
一些简单的事情:
int a = 2;
printf("a=%d\n", a);
a = 4;
printf("a=%d\n", a);
证明了这一点,它当然也适用于字符串,因为它们只是内存块。
您可以扩展上述基于malloc()
的示例:
char *dest = malloc(5);
if(dest != NULL)
strcpy(dest, "five");
printf("dest='%s'\n", dest);
strcpy(dest, "four");
printf("dest='%s'\n", dest);
strcpy(dest, "one");
printf("dest='%s'\n", dest);
它会打印出来:
dest='five'
dest='four'
dest='one'
【讨论】:
char *a = "hello";
向后兼容性实际上不受欢迎的情况
“很遗憾,您的理解并不完全正确。”认为这样。我是来学习的,我不希望是正确的:)
所以使用char *a = "hello"
将“hello”存储在只读内存中,但指向它的指针允许您修改内容?修改内容哪个是违法的,对吧?
@CSStudent 对!有点奇怪。
我得出了相同的结论,但有更多的试验和错误以及测试代码 sn-ps。如果我早点找到这个答案就好了:)【参考方案2】:
我的理解如下:
char *
指向一个字符串常量,修改它指向的数据是未定义的。但是,您可以更改它指向的位置。
这里你指的是一个表达式
char * string = "mystring";
你说得对,string[1]='r';
是未定义的。但这不是因为char *
,而是因为涉及的字符串文字以某种方式将其放入只读内存中。
比较一下
char string[] = "mystring";
我在 RAM 中定义了一个数组,将所述字符串放入其中。这里允许string[1] = 'r';
,因为我们在正常的数据内存中。
这似乎支持你的假设,但请接受:
char string[] = "mystring";
char * string2 = string;
这里string2[1] = 'r';
是有效的,因为它指向的位置也可以写入。
char[] refers to a block of memory that you can change its contents but not what it refers to.
是的,因为名称只是变量的名称,而不是指针。
strcpy(dest, src) copies src into dest.
没错。
我的问题是,将 strcpy() 与 dest 一起使用是否不正确 char * 已经指向某些东西(因为我相信旧的 内容将被 strcpy() 覆盖 - 这是未定义的 行为)?
这取决于“已经指向某物”的意思...
例如:
char *dest = malloc(5); dest = "FIVE"; char *src = malloc(5); src = "NEW!"; strcpy(dest, src); /* Invalid because chars at dest are getting
覆盖? */
这里你又把几件事搞混了。
首先,您有dest
指向一个全新的内存块。之后,你让它指向其他你不能写的地方,这块内存就丢失了(内存泄漏)。
src
也是如此。
所以strcpy()
失败了。
你可以的
char *dest = malloc(5);
char *src = "NEW!";
strcpy(dest, src);
这里dest
指向一个可写的地方,src
指向有用的数据。
【讨论】:
感谢您的详细回答。我所说的“已经指向某事”的意思是,如果我删除了mallocs
并且只有char *dest = "FIVE"
和char *src = "NEW!"
然后我使用了strcpy()
,那是合法的还是strcpy()
覆盖了dest
指向?
"或者是 strcpy()
覆盖了 dest 指向的字符串" 是的,这就是它的意思。它获取一个地址,尝试写入它,但是当它不允许在那里写入时,它会导致未定义的行为(UB)。
所以如果我有dest
指向来自malloc
的新内存块,我可以在没有UB 的情况下使用strcpy()
?
@CSSStudent 是的,这就是它的用途。但你也可以char dest[10]; strcpy(dest, "DATA");
。【参考方案3】:
快速分析:
char *dest = malloc(5);
// 'dest' is set to point to a piece of allocated memory
// (typically located in the heap)
dest = "FIVE";
// 'dest' is set to point to a constant string
// (typically located in the code-section or in the data-section)
你给变量dest
赋值了两次,很明显,第一次赋值没有意义。
就像写作:
int i = 5;
i = 6;
最重要的是,您“丢失”了分配内存的地址,因此您以后将无法释放它。
【讨论】:
【参考方案4】:char* 是指向内存地址的指针,因此您可以修改该地址中包含的信息。
char* 和 char[] 的区别在于 char[] 不是动态的,你不能改变它的大小。此外,char * 指向堆中的地址,而 char[] 存储在程序的堆栈中。
您可以将 strcpy 与指针和数组一起使用,它会起作用,因为两者的数据都可以被覆盖。
【讨论】:
“char[] 不是动态的”,并不完全正确。您可以使用 VLA,或者数组是动态分配的结构的一部分。最好是更准确地表达你的断言,而不是仅仅给出关于“char []”的笼统陈述。那或使用代码示例来澄清。以上是关于理解 char *、char[] 和 strcpy()的主要内容,如果未能解决你的问题,请参考以下文章