4

I am reviewing someone's code and the developer has assigned one struct to another. The struct contains a char array. Somehow that "works", meaning the char array from struct A does get copied to struct B (not by reference). I'm totally baffled. Can s.o. explain that to me? I have written up a little program to illustrate the "problem".

#include <stdio.h>
#include <string.h>

/**************************************
 * some define and typedef for later
 **************************************/
#define MAX_LEN (80)

typedef struct month_s
{
    char name[MAX_LEN];
} month_st;

/**************************************
 * This bit is clear.
 **************************************/
static void usingString()
{
    char mCur[MAX_LEN] = {"Jan"};
    char mNext[MAX_LEN] = {"Feb"};

    /** this doesn't compile (of course) */
    //mCur = mNext;

    /** we need a pointer/reference */
    char *pmCur = &mCur[0];

    /** however now we "copy by reference"...*/
    pmCur = &(mNext[0]);

    /** ...so this change also applies to pmCur*/
    strcpy(mNext, "Mar");

    /** ...so pmCur is now "Mar"*/
    printf("%s: %s\n", __func__, pmCur);
}

/**************************************
 * I though the same/s.th. similar
 * as above happens here. But this "works".
 * I'm surprised to see that not to be
 * the case. Can someone explain?
 **************************************/
static void usingStruct()
{
    month_st mCur = {"Jan"};
    month_st mNext = {"Feb"};

    /** I would have thought this is "copy by reference" for the string! */
    mCur = mNext;

    /** I would have thought this also overrides mCur.name
            'cause it's pointing to mNext.name now */
    strcpy(mNext.name, "Mar");

    /** how come this works??? mCur.name is still "Feb"*/
    printf("%s: %s\n", __func__, mCur.name);
}
/**************************************
 * just the main()
 **************************************/
int main()
{
    usingString();
    usingStruct();
    return 0;
}
4

4 回答 4

3

我看到了关于指针和数组之间区别的三种解释,但据我所知,它们似乎没有解决所提出的问题。

据我了解,问题是:“我知道我不能将一个数组分配给另一个数组,那么如果数组位于结构内部,我为什么要这样做呢?

答案基本上是“因为语言是这样说的”。尽管结构是聚合类型,并且很可能包含数组,但语言规范说结构是可分配的,因此结构是可分配的。这是N1256N15706.5.16.1 Simple assignment中的部分。

(在后台,编译器可能必须实现内存副本,但这是编译器的问题,而不是你的问题。)

于 2013-07-29T07:49:44.617 回答
3

您可能最惊讶的是,数组和指针在 C 中不是一回事。在您的示例中,数组成员不仅包含指向字符串的指针,还包含字符串本身。struct因此,当您将一个实例分配给另一个实例时,所有这些都将被复制。

于 2013-07-27T12:18:16.180 回答
2

根据您的结构声明:

typedef struct month_s
{
    char name[MAX_LEN];
} month_st;

sizeof(month_st)包括作为结构成员的 char 数组的空格。(请注意,您正在进行静态内存分配,name不是指针而是数组)。
因此,当您将一个 strct 变量分配给另一个变量时,它会完全复制数组(或者我们可以说sizeof(month_st))将复制总字节数)。

接下来,您要声明两个结构变量:

month_st mCur = {"Jan"};
month_st mNext = {"Feb"}; 

这两个变量的记忆mCurmNext是不同的。当您执行 assignmentnCur = mNext;时,将值mNext 复制到nCurstruct 变量的内存但两者都有单独的(他们自己的)内存。

strcpy()陈述:

strcpy(mNext, "Mar");

只影响变量mNext,它不会改变变量的内容nCur

为了您的困惑,假设您已按如下方式声明了您的结构:

typedef struct month_s
{
    char* name;
} month_st; 

仍然通过nCur = mNext;sizeof(month_st))字节从变量复制mNextnCur变量,因此仅复制地址作为name指向内存的指针。

在这种情况下,完整的数组/内存(您可能动态分配)不复制这称为Shallow copy

于 2013-07-27T12:21:48.853 回答
0

您感到困惑,因为您认为mCur并且mNext是指向对象的指针,而实际上它们是对象。该结构month_s仅在内存中分配空间来存储月份名称。它不分配内存来存储指向任何东西的指针。因此,当mCur分配 的值时mNext,整个对象将被复制,因为它是按值复制的,而不是按引用复制的。

为方便起见,我对您的代码进行了注释:

static void usingStruct()
{
    month_st mCur = {"Jan"};
    month_st mNext = {"Feb"};

    /** mCur and mNext are both objects. Assigning one to the other 
      * will copy by value and not by reference (as there is no reference
      * to be copied in the first place). After this assignment, 
      * mCur == {"Feb"}  */
    mCur = mNext;

    /** mNext.name is the address of the memory allocated to the object
      * mNext. This line copies the characters "Mar" to the first three
      * bytes of this memory allocation */
    strcpy(mNext.name, "Mar");

    /** At this point, mCur == {"Feb"} and mNext == {"Mar"} */
    printf("%s: %s\n", __func__, mCur.name);
}
于 2013-07-27T12:27:33.223 回答