-3

可能重复:
为什么我不能在 char* 中编辑 char?

char *k ;

void ffill()
{
    char *d="ddddd";    
    *k=*d; //expecting to copy "ddddd" to *k
    cout<<k<<"\n";
    *d[1]=5; // trying to change array element
    cout<<k<<"\n";
}

int _tmain(int argc, _TCHAR* argv[])
{
    ffill();
    cout<<k<<"\n";
}

过程填充在局部变量的帮助下初始化字符数组 k。我不确定它复制"ddddd"变量指针(这是错误的,因为在自动销毁 d 内存后不安全)或者它复制值并在此之后*k正确初始化。

如何获得*d数组元素?编译器不高兴*d[1]=5;

4

6 回答 6

17

(免责声明:此答案仅涵盖 C++。不建议同时要求 C 和 C++,因为两种语言完全不同)

序幕

char *k ;

这声明了一个指向字符的指针。

"ddddd"

这个表达式的类型char const[6]是 ,即一个由六个常量字符组成的数组。这种类型的表达式可以隐式转换为指向数组第一个元素的指针。该指针的类型是char const*,即指向常量字符的指针。Achar const*不能转换为 a char*,因为char*它允许修改它指向的字符,而char const*不允许修改。

char *d="ddddd";

由于上述规则,这种说法是不正确的。您应该打开编译器上的警告,它会警告您不要这样做(理想情况下它实际上是一个错误,而不仅仅是一个警告)。char const* d = "ddddd";如果你真的想要一个指针或者char d[] = "ddddd";你想要一个数组,它应该是。第二种形式不需要const,因为它会制作副本,因此不会冒更改原始数据的风险,即const.

*d

这个表达式涉及到上面提到的隐式转换char const*,然后*对它应用间接运算符(the),从而产生一个类型为 的表达式char const&,即对常量字符的引用。

*k

与 类似*d,这对指针执行间接操作。在这种情况下,k是 type char*,所以结果表达式是 type char&

*k=*d; //expecting to copy "ddddd" to *k

赋值分配单个字符,因为它是从对常量字符的引用到字符的引用的赋值。它最终将字符串的第一个字符分配给 指向的字符k,即……等等。

k指向哪里?它从未初始化!这注定以悲剧收场。

第1章

那么,我们如何k指向某个地方呢?我们如何将整个字符串从该空间复制d到该空间中?

要将d数组的六个字符复制到中k,我们需要六个字符的空间。最简单的方法是创建一个包含六个字符的数组。

char k[6];

现在,如何复制这六个元素?我们可以使用 C 库函数strcpy,它复制以空字符结尾的字符串。使用此功能需要非常小心,因为:

  1. 它要求源有一个 null ( '\0') 字符标记结束;如果源没有这样的字符,则行为未定义,任何事情都可能发生。这就是字符串"ddddd"有六个字符而不是 5 个的原因:\0编译器会在末尾为您插入一个隐式字符。

  2. 它要求目标有足够的空间容纳包括 空终止符在内的整个源字符串。如果目的地没有足够的空间,则行为也未定义,任何事情都可能发生。

这就是如何使用此函数来制作字符串的副本:

std::strcpy(k, d);

未能满足第 1 点或第 2 点可能会导致任何事情,从程序看似正常工作(如果你不走运),到以奇怪的方式随机运行,再到简单地崩溃(如果你幸运的话)。

结语

伙计,这是很多信息。C++ 程序员必须一直关心这些问题吗?那一定很烦人。

好吧,C++ 程序员可以使用std::string字符数组来代替字符数组,这样就少了很多麻烦:我们可以使用赋值运算符进行复制,我们不需要跟踪正确的大小,我们不需要关心是否有 null终止符到位,我们不需要在编译时限制大小,还有很多其他优点。

std::string k;

void ffill()
{
    std::string d="ddddd";    
    k = d;
    cout<<k<<"\n";
    d[1]=5;
    cout<<k<<"\n";
}
于 2012-07-23T15:20:16.357 回答
1

使用 C 编程语言,您应该使用数组而不是指针(因为它可能指向只读字符串)。例如 :

char *k;

void 
fill(void)
{
   char d[] = "ddddd";
   k = d;
   d[1] = '5'; // Did you mean '5' ? 
}
于 2012-07-23T14:52:08.327 回答
1

就像 Martinho Fernandes 已经说过的那样:您似乎正在尝试使用 'std:string',而不是 char 数组。

char k[20] ; //*k doesn't allocate any memory for you to use.

void ffill()
{
    char *d="ddddd";    //This works, since it points to the constant character string in your code. But it can not be altered in any way. (It's a 'const char *')
    strcpy(k, d);       //This standard function copies the content of one pointer to another.
    cout<<k<<"\n";      //Not too sure, but it should work,
    k[1]=5;             //k is the 'changeable memory, not 'd'.
    cout<<k<<"\n";
}
于 2012-07-23T14:54:58.933 回答
1

您需要注意这里发生的几件事。让我试着解释一下:

char *k ;

这一行声明了一个名为的变量k,它是一个字符的指针。但是,它没有初始化为指向任何东西。尝试使用未初始化的指针将导致未定义的行为。

void ffill() 
{ 
    char *d="ddddd";

这一行声明了一个名为的变量d,它也是一个字符的指针。同时,将指针初始化为指向一个常量字符数组(也称为 c 字符串),该数组包含 5 个 'd' 字符和一个终止 NULL 字符(因此该数组有 6 个元素)。

    *k=*d; //expecting to copy "ddddd" to *k 

此行使用取消引用运算符 (*)。该运算符复制 所指向的字符d并将其放置在 所指向的地址处k。正如我上面提到的,这将导致未定义的行为,因为指针中的地址k尚未初始化。

    cout<<k<<"\n";
    *d[1]=5; // trying to change array element

首先,您正在尝试将 int 分配给 char。C 和 C++ 都允许这样做,但您可能不会得到您期望的结果。在这种情况下,您试图用字符代码 5 替换第二个 'd' 字符。在 ASCII 中,这是一个非打印字符。

此外,由于d指向 c 字符串常量,因此尝试更改其元素会导致未定义的行为。

    cout<<k<<"\n";
}

int _tmain(int argc, _TCHAR* argv[])
{
    ffill();
    cout<<k<<"\n";
}

将一个 c-string 复制到另一个 c-string 还有一些其他问题,但这是我将在这里讨论的所有细节。正如其他人提到的,使用 std::string 更简单。但是,我也相信学习如何使用 c-strings 很有教育意义,可以提高你的编码技能。

于 2012-07-23T15:03:43.770 回答
0

您需要声明d为数组而不是指针。:

char d[]
d[1] = '5';   // d is a char array, so did you mean the character '5'?

并更改 *k=*d;k = d; //This will copy the value of the pointer

于 2012-07-23T14:53:38.533 回答
0

让我们来看看:

*k=*d; //expecting to copy "ddddd" to *k

这不会复制“字符串”,只会尝试将指向的内存设置kd. 如果它没有被初始化,那么它将严重失败。

*d[1]=5; // trying to change array element

这也会失败。首先,这是一个双重间接。会d[1] = 5;被打赌,但这也会失败,因为字符串很可能存储在只读内存中。

改用字符串。

于 2012-07-23T14:55:21.850 回答