【问题标题】:Pass struct by reference in C在 C 中通过引用传递结构
【发布时间】:2010-11-30 16:57:22
【问题描述】:

这段代码正确吗?它按预期运行,但是这段代码是否正确使用了结构的指针和点表示法?

struct someStruct {
 unsigned int total;
};

int test(struct someStruct* state) {
 state->total = 4;
}

int main () {
 struct someStruct s;
 s.total = 5;
 test(&s);
 printf("\ns.total = %d\n", s.total);
}

【问题讨论】:

  • 为什么 test 应该返回一个 int ?实际上那里没有回报。
  • C 有引用吗?惊讶...
  • @honk:不是 C++ 意义上的,而是在 C++ 发明之前,指针是一种“引用”(因为它们有一个“引用对象”)。现在他们有一个“指针”或一些这样的废话。由于someStruct 具有值语义,因此“按引用传递”(C 在 C++ 术语中不这样做)与“按值传递引用”完全相同(它确实是有问题的“引用”是一个指针)。
  • c++ 引用(用 & 符号声明)的优势在于:1) 使用 c++ 引用编写错误的可能性较小,2) 使用 c++ 引用编写的代码更有可能启用编译器进行别名优化。由于在 fortran 中不可能使用别名,因此 c 中未优化的指针例程可能会导致尴尬。

标签: c struct


【解决方案1】:

您对指针和点表示法的使用很好。如果出现问题,编译器应该会给你错误和/或警告。

这里是您的代码的副本,其中包含一些额外的注释和需要考虑的事项,例如结构和指针的使用以及函数和变量的范围。

注意: 下面源代码示例中的代码编写差异是我在函数定义/声明中的结构名称之后和星号之前放置了一个空格,如struct someStruct *p1; 和 OP 放置了一个星号后的空格,如struct someStruct* p1;。编译器没有区别,只是程序员的可读性和习惯不同。我更喜欢将星号放在变量名旁边,以明确星号更改了它旁边的变量名。如果我在声明或定义中有多个变量,这一点尤其重要。编写struct someStruct *p1, *p2, var1; 将创建两个指针p1p2,以及一个变量var1。写入struct someStruct* p1, p2, var1; 将创建单个指针p1 和两个变量p2var1

// Define the new variable type which is a struct.
// This definition must be visible to any function that is accessing the
// members of a variable of this type.
struct someStruct {
    unsigned int total;
};

/*
 * Modifies the struct that exists in the calling function.
 *   Function test() takes a pointer to a struct someStruct variable
 *   so that any modifications to the variable made in the function test()
 *   will be to the variable pointed to.
 *   A pointer contains the address of a variable and is not the variable iteself.
 *   This allows the function test() to modify the variable provided by the
 *   caller of test() rather than a local copy.
 */
int test(struct someStruct *state) {
    state->total = 4;
    return 0;
}

/* 
 * Modifies the local copy of the struct, the original
 * in the calling function is not modified.
 * The C compiler will make a copy of the variable provided by the
 * caller of function test2() and so any changes that test2() makes
 * to the argument will be discarded since test2() is working with a
 * copy of the caller's variable and not the actual variable.
 */
int test2(struct someStruct state) {
    state.total = 8;
    return 0;
}

int test3(struct someStruct *state) {
    struct someStruct  stateCopy;
    stateCopy = *state;    // make a local copy of the struct
    stateCopy.total = 12;  // modify the local copy of the struct
    *state = stateCopy;    /* assign the local copy back to the original in the
                              calling function. Assigning by dereferencing pointer. */
    return 0;
}

int main () {
    struct someStruct s;

    /* Set the value then call a function that will change the value. */
    s.total = 5;
    test(&s);
    printf("after test(): s.total = %d\n", s.total);

    /*
     * Set the value then call a function that will change its local copy 
     * but not this one.
     */
    s.total = 5;
    test2(s);
    printf("after test2(): s.total = %d\n", s.total);

    /* 
     * Call a function that will make a copy, change the copy,
       then put the copy into this one.
     */
    test3(&s);
    printf("after test3(): s.total = %d\n", s.total);

    return 0;
}

【讨论】:

  • 将“*”放在变量名称之前(如本文中所做的那样)或类型名称之后(如 OP 所做的那样)有什么意义?这里:int test(struct someStruct *state) OP:int test(struct someStruct* state)
  • @ALM 在为变量指定类型时,星号表示它是指向该类型变量的指针。所以someStruct state 是一个someStruct 类型的变量,而someStruct *state 是一个指向someStruct 类型变量的指针。见Pointer Basics
  • 感谢您的回复;但是,我的问题不是 * 的用途,我的问题是在结构的类型名之后具有 * (a)和(b)在结构的指定名称之前具有 * 的意义是什么。我希望这让我的任务更清晰。
  • @ALM,对不起,但您的澄清没有澄清。不确定“分配的结构名称”是什么意思。也许您的意思是我在声明中的结构名称后放了一个空格,而 OP 在名称后放了一个空格?编译器没有区别,只是可读性和习惯不同。我更喜欢将星号放在变量名旁边,因为如果我在声明中有多个变量。 struct someStruct *p1, *p2, var1; 将创建两个指针和一个变量。 struct someStruct* p1, p2, var1; 将创建单个指针 p1 和两个变量 p2 和 var1`。
  • 是的。这正是我问的。非常感谢您清除它
【解决方案2】:

这是结构体的正确用法。对您的返回值有疑问。

另外,由于您正在打印一个无符号整数,您应该使用%u 而不是%d

【讨论】:

    【解决方案3】:

    是的,没错。它创建了一个结构s,将其总数设置为5,将指向它的指针传递给使用该指针将总数设置为4的函数,然后将其打印出来。 -> 用于指向结构的指针的成员,. 用于结构的成员。就像你使用它们一样。

    虽然返回值不同。 test 应该是无效的,main 需要一个 return 0 在其末尾。

    【讨论】:

      【解决方案4】:

      是的。这是正确的。如果不是(从 . / -> 的角度来看),您的编译器会大喊大叫。

      【讨论】:

        【解决方案5】:

        是的,它对结构的正确使用。你也可以使用

        typedef struct someStruct {
         unsigned int total;
        } someStruct;
        

        这样你就不必一次又一次地写struct someStruct s;,但可以使用someStruct s;

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-05-12
          • 2011-02-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-11-14
          • 2012-01-04
          相关资源
          最近更新 更多