char数组 - 处理内存

时间:2012-07-23 14:48:34

标签: c++ c arrays c-strings

  

可能重复:
  Why can't I edit a char in a 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;

不满意

6 个答案:

答案 0 :(得分:17)

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

序言

char *k ;

这声明了一个指向角色的指针。

"ddddd"

此表达式具有类型char const[6],即六个常量字符的数组。可以将此类型的表达式隐式转换为指向数组第一个元素的指针。该指针的类型是char const*,即指向常量字符的指针。 char const*无法转换为char*,因为char*允许修改其指向的字符,而char const*则不允许。

char *d="ddddd";

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

*d

此表达式涉及到上面提到的char const*的隐式转换,然后将间接运算符(*)应用于它,从而生成类型为char const&的表达式,即,对常数字符的引用。

*k

*d类似,它对指针执行间接寻址。在这种情况下,k的类型为char*,因此生成的表达式的类型为char&

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

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

k指向哪里?它从未被初始化!这必将以悲剧告终。

第1章

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

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

char k[6];

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

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

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

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

    std::strcpy(k, d);
    

    如果没有遇到#1或#2点,可能会导致任何事情,从看似正在运作的程序(如果你运气不好),以奇怪的方式随机行动,简单地崩溃(如果你很幸运)。< / p>

    后记

    男人,这是很多信息。 C ++程序员是否必须始终关注这些问题?那一定很烦人。

    好吧,C ++程序员可以使用std::string而不是字符数组,并且可以减少麻烦:我们可以使用赋值运算符进行复制,我们不需要跟踪正确的大小,我们不要需要关注空终止符,我们不需要在编译时限制大小,以及其他一些优点。

    std::string k;
    
    void ffill()
    {
        std::string d="ddddd";    
        k = d;
        cout<<k<<"\n";
        d[1]=5;
        cout<<k<<"\n";
    }
    

答案 1 :(得分:1)

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

char *k;

void 
fill(void)
{
   char d[] = "ddddd";
   k = d;
   d[1] = '5'; // Did you mean '5' ? 
}

答案 2 :(得分: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";
}

答案 3 :(得分:1)

这里有几件你需要注意的事情。让我试着解释一下:

char *k ;

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

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

此行声明一个名为d的变量,它也是一个指向字符的指针。同时,将指针初始化为指向包含5'd字符和终止NULL字符的常量字符数组(也称为c字符串)(因此数组有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 ++都允许这样做,但你可能无法得到你所期望的。在这种情况下,您尝试将第二个“d”字符替换为字符代码5.在ASCII中,这是一个非打印字符。

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

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

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

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

答案 4 :(得分: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

答案 5 :(得分:0)

让我们看看:

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

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

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

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

改用字符串。