简体   繁体   English

为什么我们不能将字符串复制到字符指针何时我们可以直接为其指定字符串?

[英]Why Can't we copy a string to Character Pointer WHEN we can assign a string directly to it?

This code produces "p = hello world": 这段代码产生“p = hello world”:

#include "stdio.h"
#include "string.h"

int main(){
    char *p;
    p="hello world";
    printf("p is %s \n",p);
    return 0;
}

But this code produces a segmentation fault: 但是这段代码产生了一个分段错误:

#include "stdio.h"
#include "string.h"

int main() { 
    char *p;
    strcpy(p,"hello");
    printf("p is %s \n",p);
    return 0;
}

and this code produces "p = hello" 这段代码产生“p = hello”

#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int main() {
  char *p;
  p=(char*)malloc (10);
  strcpy(p,"hello");
  printf("p is %s \n",p);
  return 0;

} }

In the case where p="hello world"; p="hello world";的情况下p="hello world"; (1st case at the time of this edit), p is being initialized to point to a read-only memory region which contains the string "hello world" (string literal). (在该编辑时的第一种情况), p被初始化为指向包含字符串“hello world”(字符串文字)的只读存储器区域。 This read-only memory region is created at compile time. 只读存储器区域在编译时创建。

In the case that causes the segmentation fault (2nd case at the time of this edit), p is uninitialized and copying anything to it will produce unpredictable results because the location in memory that p is pointing to is not specified by the code. 在导致分段错误的情况下(此编辑时的第二种情况), p未初始化并且向其复制任何内容将产生不可预测的结果,因为代码未指定p指向的内存中的位置。

Before you can copy a string to p , you must specify the memory that p is pointing to. 在将字符串复制到p ,必须指定p指向的内存。

You can allocate this memory on the stack 您可以在堆栈上分配此内存

char buf[BUFSIZ] = ""; /* local variable */

on the heap 在堆上

char *buf = malloc(BUFSIZ); /* don't forget to free */

or in the __DATA segment. 或在__DATA段。

static char buf[BUFSIZ] = ""; /* global variable */

You can then initialize p to point at the memory buffer. 然后,您可以初始化p以指向内存缓冲区。

char *p = buf;

This is similar in concept to initializing p to point to the string literal in read-only memory. 这在概念上类似于初始化p以指向只读存储器中的字符串文字。 Unlike the case where p points to the string literal, you can now copy a string to the character pointer as it does not point to read-only memory. p指向字符串文字的情况不同,您现在可以将字符串复制到字符指针,因为它不指向只读内存。

Note: I intentionally created a separate buffer and initialized p to point to it to help make my point. 注意:我有意创建了一个单独的缓冲区并初始化了p以指向它以帮助说明我的观点。

The reason is that when you declare a pointer, it doesn't actually point to anything useful. 原因是当你声明一个指针时,它实际上并没有指向任何有用的东西。 strcpy requires a block of memory for the string to be copied into. strcpy需要一个内存块才能将字符串复制到其中。 It will not do this for you automatically. 它不会自动为您执行此操作。

From the documentation (emphasis mine): 从文档(强调我的):

Copies the C string pointed by source into the array pointed by destination, including the terminating null character. 将source指向的C字符串复制到destination指向的数组中,包括终止空字符。

To avoid overflows, the size of the array pointed by destination shall be long enough to contain the same C string as source (including the terminating null character) , and should not overlap in memory with source. 为避免溢出, 目标指向的数组大小应足够长,以包含与源相同的C字符串(包括终止空字符) ,并且不应在内存中与源重叠。

You need to make this true, as it is a precondition of the function. 你需要将其设为true,因为它是函数的前提条件。

Also, in the parameters section: 另外,在参数部分:

destination 目的地

 Pointer to the destination array where the content is to be copied. 

You need to make sure destination is a pointer to an array. 您需要确保destination是指向数组的指针。

There is no free lunch - you need to grab & manage memory. 没有免费的午餐 - 你需要抓住和管理记忆。 If you just assume that because you have access to a pointer memory should be there then you'll run into unspecified behavior (segfault likely). 如果您只是假设因为您可以访问指针内存应该存在,那么您将遇到未指定的行为(可能是段错误)。

Because in the first example the pointer p contains some random garbage that happens to be on the stack at the time, might be zero, might be anything else, so it points to ... nobody knows where, your code segment, for example. 因为在第一个例子中,指针p包含当时恰好在堆栈上的一些随机垃圾,可能是零,可能是其他任何东西,所以它指向......没人知道你的代码段在哪里,例如。 The OS does the right thing and tells you that you are breaking the rules and trying to write to memory that doesn't belong to you. 操作系统做正确的事情并告诉您,您违反规则并尝试写入不属于您的内存。 Read the fine description of segmentation faults here . 在这里阅读细分错误的精细描述

If you absolutely want to avoid dynamic memory allocation and you know the size of the source string at compile time you can grab appropriate stack space like this: 如果您绝对想要避免动态内存分配, 并且 在编译时知道源字符串的大小,则可以获取适当的堆栈空间,如下所示:

char buffer[6]; /* strlen( "hello" ) + 1 for zero terminator */
strcpy( buffer, "hello" );

But that is a dangerous road leading to buffer overruns . 但这是一条导致缓冲超支的危险道路。

Notice what the two working examples have in common: they have a p = line that assigns something to p . 请注意两个工作示例的共同点:它们有一个p =行,用于为p分配内容。 The non-working example does not do this. 非工作示例不会这样做。

Consider this line (from the first example): 考虑这一行(来自第一个例子):

p = "hello world";

Although it might look like it's "copying a string to a char pointer", it's not. 虽然它可能看起来像是“将字符串复制到char指针”,但事实并非如此。 It's copying the location of a string to a pointer-to-char. 它正在将字符串的位置复制到指向char的指针。 That's what a pointer-to-char like p stores - the location of a contiguous block of char s. 这就是像p存储一样指向char的指针 - 一个连续的char块的位置。

Similarly, consider this line from the third example: 同样,请考虑第三个示例中的这一行:

p = malloc(10);

This is also copying a location - it's copying the location of a block of 10 unintialised char s into p . 这也是复制的位置-这是复制的10 unintialised块的位置, char s转换p

strcpy(dest, source) copies characters from the location given by source to the location given by dest . strcpy(dest, source)字符从source给定的位置复制到dest给出的位置。 It should be clear that if you never set p to a valid location, then strcpy(p, "hello") can't do anything sensible - in your second example, p is an essentially random location, and you then ask strcpy() to copy something to that location. 应该很清楚,如果你从未将p设置为有效位置,那么strcpy(p, "hello")不能做任何明智的事情 - 在你的第二个例子中, p是一个基本上随机的位置,然后你问strcpy()将某些东西复制到该位置。

There are two distinct parts to memory copying. 内存复制有两个不同的部分。 The first is the memory occupied by the item you want to copy (which you create in your example using the malloc() function), and the second is a pointer to that block of memory (which you call p). 第一个是您要复制的项目所占用的内存(使用malloc()函数在您的示例中创建),第二个是指向该内存块的指针(您将其称为p)。 These two entities must be set up for the destination too, before you can do a copy. 在进行复制之前,还必须为目标设置这两个实体。 In your first example that fails, you have not set up the memory block for the destination (but it has been set for the source implicitly when you declare the string hello ). 在第一个失败的示例中,您尚未为目标设置内存块(但是在声明字符串hello时已隐式设置了内存块)。

Yes its annoying. 是的,这很烦人。 You can use strdup to shorten it: 您可以使用strdup来缩短它:

char *p = strdup("hello");
printf("p is %s \n",p);

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

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