在C中声明指针的方法 我只学习C不到一个星期(我的C++和其他语言的知识有帮助),我对指针和声明方式感到困惑。

在C中声明指针的方法 我只学习C不到一个星期(我的C++和其他语言的知识有帮助),我对指针和声明方式感到困惑。,c,pointers,malloc,C,Pointers,Malloc,下面,我使用一个名为Object的简单结构: struct对象{int id;}; 以下用于创建指针的方法是否以不同的方式执行相同的操作 struct Object obj1={.id=1}; 结构对象*obj1\u p=&obj1;//获取指针的方法1 //同样,只是复合文字? 结构对象*obj2_p=&(结构对象){.id=1};//获取指针的方法2 //除了未初始化之外,这是相同的吗? struct Object*obj3_p=malloc(sizeof(struct Object));

下面,我使用一个名为Object的简单结构:

struct对象{int id;};
以下用于创建指针的方法是否以不同的方式执行相同的操作

struct Object obj1={.id=1};
结构对象*obj1\u p=&obj1;//获取指针的方法1
//同样,只是复合文字?
结构对象*obj2_p=&(结构对象){.id=1};//获取指针的方法2
//除了未初始化之外,这是相同的吗?
struct Object*obj3_p=malloc(sizeof(struct Object));//获取指针的方法2
是否有一段时间你只能使用一种方法

另外,作为旁注,为什么有些人投malloc,这样做更好吗

//malloc被强制转换为对象:
struct Object*obj3_p=(Object*)malloc(sizeof(struct Object));
这两种“方法”的作用完全相同。正如你所说,第二个只是一个例子


这将为
struct对象
分配足够的内存,而无需对其进行初始化。而不是您,因为
malloc
返回
void*
,它会自动安全地升级到任何其他指针。但是如果您这样做,您应该将其强制转换为
struct Object*
,而不是
Object*

struct Object *obj3_p = (struct Object*) malloc(sizeof(struct Object));
不过看起来很笨重。。。我更喜欢这样做:

struct Object *obj3_p = malloc(sizeof *obj3_p);
这两种“方法”的作用完全相同。正如你所说,第二个只是一个例子


这将为
struct对象
分配足够的内存,而无需对其进行初始化。而不是您,因为
malloc
返回
void*
,它会自动安全地升级到任何其他指针。但是如果您这样做,您应该将其强制转换为
struct Object*
,而不是
Object*

struct Object *obj3_p = (struct Object*) malloc(sizeof(struct Object));
不过看起来很笨重。。。我更喜欢这样做:

struct Object *obj3_p = malloc(sizeof *obj3_p);

我写了这段代码,希望它能帮助您更好地理解指针的一些特性:

#include <stdio.h>
#include <stdlib.h>

struct Object { int id; };

struct Object *getObjectBold() {
    struct Object* obj2_p = &(struct Object) { .id = 2 };

    return obj2_p; // UB: Returns the address of a local object (the compound literal).
}

struct Object *getObject() {
    struct Object* obj3_p = malloc(sizeof(*obj3_p)); // Better way of calling malloc than using sizeof(struct Object).
    obj3_p->id = 3; // You don't need to do this.

    return obj3_p; // This needs to be freed later on!
}

int main(void) {
    struct Object obj1 = { .id = 1 };
    struct Object* obj1_p = &obj1;
    
    printf("obj1.id = %d\n", obj1_p->id); 
    obj1_p->id = 10; // You can change values using the pointer
    printf("obj1.id = %d\n", obj1_p->id); 

    // The only different thing with this case is that you don't
    // "lose" your object when setting the pointer to NULL 
    // (although you can only access it through the object, not through the pointer).

    obj1_p = NULL;
    printf("obj1.id = %d\n", obj1_p->id); // This won't work (undefined behaviour).
    printf("obj1.id = %d\n", obj1.id); // This will.


    struct Object* obj2_p = &(struct Object) { .id = 1 };
    obj2_p->id = 2; // You can change the id
    printf("obj2.id = %d\n", obj2_p->id);

    // If you make this pointer point to another address, you "lose" your object.
    obj2_p = NULL;
    printf("obj2.id = %d", obj2_p->id); // This won't work at all (undefined behaviour).


    // Both of these pointers point to objects in the stack, so, for example,
    // they don't work when returning from a function.
    obj2_p = getObjectBold();
    obj2_p->id = 20; // This won't work (undefined behaviour).
    printf("obj2.id = %d\n", obj2_p->id); // This works if you don't dereference the pointer.


    // The third case is not the same as the other two, since you are allocating memory on the heap.
    // THIS is a time where you can only use one of these three methods.
    struct Object *obj3_p = getObject(); // This works!
    printf("obj3.id = %d\n", obj3_p->id);
    obj3_p->id = 30; // This works now.
    printf("obj3.id = %d\n", obj3_p->id);

    free(obj3_p); // You need to do this if you don't want memory leaks.

    return 0;
}
我建议您查看这些链接,它们对我很有帮助:


    • 我写了这段代码,希望它能帮助您更好地理解指针的一些特性:

      #include <stdio.h>
      #include <stdlib.h>
      
      struct Object { int id; };
      
      struct Object *getObjectBold() {
          struct Object* obj2_p = &(struct Object) { .id = 2 };
      
          return obj2_p; // UB: Returns the address of a local object (the compound literal).
      }
      
      struct Object *getObject() {
          struct Object* obj3_p = malloc(sizeof(*obj3_p)); // Better way of calling malloc than using sizeof(struct Object).
          obj3_p->id = 3; // You don't need to do this.
      
          return obj3_p; // This needs to be freed later on!
      }
      
      int main(void) {
          struct Object obj1 = { .id = 1 };
          struct Object* obj1_p = &obj1;
          
          printf("obj1.id = %d\n", obj1_p->id); 
          obj1_p->id = 10; // You can change values using the pointer
          printf("obj1.id = %d\n", obj1_p->id); 
      
          // The only different thing with this case is that you don't
          // "lose" your object when setting the pointer to NULL 
          // (although you can only access it through the object, not through the pointer).
      
          obj1_p = NULL;
          printf("obj1.id = %d\n", obj1_p->id); // This won't work (undefined behaviour).
          printf("obj1.id = %d\n", obj1.id); // This will.
      
      
          struct Object* obj2_p = &(struct Object) { .id = 1 };
          obj2_p->id = 2; // You can change the id
          printf("obj2.id = %d\n", obj2_p->id);
      
          // If you make this pointer point to another address, you "lose" your object.
          obj2_p = NULL;
          printf("obj2.id = %d", obj2_p->id); // This won't work at all (undefined behaviour).
      
      
          // Both of these pointers point to objects in the stack, so, for example,
          // they don't work when returning from a function.
          obj2_p = getObjectBold();
          obj2_p->id = 20; // This won't work (undefined behaviour).
          printf("obj2.id = %d\n", obj2_p->id); // This works if you don't dereference the pointer.
      
      
          // The third case is not the same as the other two, since you are allocating memory on the heap.
          // THIS is a time where you can only use one of these three methods.
          struct Object *obj3_p = getObject(); // This works!
          printf("obj3.id = %d\n", obj3_p->id);
          obj3_p->id = 30; // This works now.
          printf("obj3.id = %d\n", obj3_p->id);
      
          free(obj3_p); // You need to do this if you don't want memory leaks.
      
          return 0;
      }
      
      我建议您查看这些链接,它们对我很有帮助:


        • 你的问题中有两个截然不同的主题

          struct  Object* obj1_p = .......; 
          ^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^
          pointer object           initialization
          definition
          
        • 指针变量定义
        • 只能以一种方式定义指针变量:

          type *objectname;
          
        • 初始化将值分配给指针变量。此值应引用与指针类型相同的有效对象或大小不小于指针类型的有效内存。示例中的不同之处在于引用对象的创建方式
        • 是否有一段时间你只能使用一种方法

          这只取决于程序逻辑。您只需记住基础对象的作用域,以避免取消引用不存在于特定作用域之外的对象:

          struct Object *valid1(void)   //valid
          {
              struct Object* obj3_p = malloc(sizeof(*obj3_p)); 
          
              return obj3_p;
          }
          
          struct  Object obj1 = { .id = 1 };
          struct Object *valid2(void)   // valid
          {
              struct Object* obj3_p = &obj1; 
          
              return obj3_p;
          }
          
          struct Object *invalid1(void)   // invalid
          {
              struct  Object obj1 = { .id = 1 };
              struct Object* obj3_p = &obj1; 
          
              return obj3_p;
          }
          
          struct Object *invalid2(void)   // invalid
          {
              struct Object* obj3_p = &(struct Object){ .id = 1 };
          
          
              return obj3_p;
          }
          
          另外,作为旁注,为什么有些人投马洛克,它更好吗 去做吗

          如果没有
          malloc
          的原型,它会使警告静音,因此被视为不良做法。最好不要投。现代编译器和最新的C标准不允许在没有原型的情况下使用函数


          最好使用
          sizeof(object)
          而不是
          sizeof(type)
          来更改对象的类型,就像您需要更改程序中出现的
          sizeof(type)
          的oll一样。很容易漏掉一些错误,也很难发现错误。

          在你的问题中有两个截然不同的主题

          struct  Object* obj1_p = .......; 
          ^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^
          pointer object           initialization
          definition
          
        • 指针变量定义
        • 只能以一种方式定义指针变量:

          type *objectname;
          
        • 初始化将值分配给指针变量。此值应引用与指针类型相同的有效对象或大小不小于指针类型的有效内存。示例中的不同之处在于引用对象的创建方式
        • 是否有一段时间你只能使用一种方法

          这只取决于程序逻辑。您只需记住基础对象的作用域,以避免取消引用不存在于特定作用域之外的对象:

          struct Object *valid1(void)   //valid
          {
              struct Object* obj3_p = malloc(sizeof(*obj3_p)); 
          
              return obj3_p;
          }
          
          struct  Object obj1 = { .id = 1 };
          struct Object *valid2(void)   // valid
          {
              struct Object* obj3_p = &obj1; 
          
              return obj3_p;
          }
          
          struct Object *invalid1(void)   // invalid
          {
              struct  Object obj1 = { .id = 1 };
              struct Object* obj3_p = &obj1; 
          
              return obj3_p;
          }
          
          struct Object *invalid2(void)   // invalid
          {
              struct Object* obj3_p = &(struct Object){ .id = 1 };
          
          
              return obj3_p;
          }
          
          另外,作为旁注,为什么有些人投马洛克,它更好吗 去做吗

          如果没有
          malloc
          的原型,它会使警告静音,因此被视为不良做法。最好不要投。现代编译器和最新的C标准不允许在没有原型的情况下使用函数


          最好使用
          sizeof(object)
          而不是
          sizeof(type)
          来更改对象的类型,就像您需要更改程序中出现的
          sizeof(type)
          的oll一样。很容易遗漏一些错误,也很难发现错误。

          首先,让我们理清一些术语-

          您以完全相同的方式声明所有三个指针:
          struct Object* objn_p ...
          声明说明符是
          struct Object
          ,声明符是
          *obj1\u p
          ,初始值设定项是
          =&obj\u 1

          我知道声明指针对象的C++约定是“代码> t*p< /COD>,但是语法实际上是代码> T(*p)< /COD> -<代码> */COD>运算符总是绑定到声明符而不是类型说明符。如果你写

          T*p,q
          则只有
          p
          被声明为指向
          T
          的指针
          q
          被声明为
          T
          的一个实例。我知道为什么C++约定存在,我知道它的合理性,但是它确实错误地说明了声明语法在C和C++中都是如何工作的,我认为使用它是错误的。大多数C程序员将使用
          struct Object *obj2_p = &(struct Object){ .id = 1 };
          
          printf( "%d %d %d", obj1.id, obj1_p->id, (*obj1_p).id );
          
          printf( "%d %d", obj2_p->id, (*obj2_p).id );
          
          struct Object *obj3_p = malloc( sizeof( struct Object ) );
          
          int *p = (int *) malloc( sizeof *p * N );
          
          int *p = NULL;
          ...
          p = (int *) malloc( sizeof *p * N );
          
          int *p = malloc( sizeof *p * N );
          
          int *p = NULL;
          ...
          p = malloc( sizeof *p * N );