在C语言中,int *和int *[100]这两种类型有什么区别?

12

我是一名有帮助的助手,可以为您翻译以下内容:

作为一个新手,请不要对我太苛刻。

下面这些代码有什么区别?

int *p;         //As i understand, it creates a pointer to an variable of size int.
int *p[100];    //Don't really know what this is.
int (*p)[100];  // I have come to understand that this is a pointer to an array. 

你是只问关于C语言的问题,还是想了解C++的答案呢? - benjymous
7
请参见cdecl.org - Sven Marnach
@Sven Marnach,char ((**foo[][8])())[]?我们需要更深入。 - kvv
@benjymous,我想听一些关于C++指针的有趣内容。 - kvv
请不要对这个问题进行负评。虽然这个问题已经被回答了很多次,但是我们仍然可以找到一些好的答案。 - haccks
4个回答

41
  1. This is a pointer to an int:

    int *p;
    
    ┌────┐
    │int*│
    └────┘
    

    It should point at an int, something like this:

    ┌────┐
    │int*│
    └─┃──┘
      ▼
    ┌───┐
    │int│
    └───┘
    
  2. This is an array of 100 pointers to int:

    int *p[100];
    

    That is, it gives you 100 pointers.

    ┌────┬────┬────┬────┬────┬────┬┄
    │int*│int*│int*│int*│int*│int*│
    └────┴────┴────┴────┴────┴────┴┄
    

    Each pointer should point an int, perhaps like this:

    ┌────┬────┬────┬────┬────┬────┬┄
    │int*│int*│int*│int*│int*│int*│
    └─┃──┴─┃──┴─┃──┴─┃──┴─┃──┴─┃──┴┄
      ▼    ▼    ▼    ▼    ▼    ▼
    ┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐┌┄
    │int││int││int││int││int││int││
    └───┘└───┘└───┘└───┘└───┘└───┘└┄
    

    Of course, there's no reason they can't all point at the same int, or whatever.

    You may want to use an array of pointers if you want many pointers that you can easily iterate over. You may, for example, dynamically allocate objects and have each pointer point at a different object:

    p[0] = new int(0);
    p[1] = new int(0);
    // ...
    

    Perhaps dynamically allocating ints isn't the best example, but I think the point is clear.

  3. This is a pointer to an array of 100 int:

    int (*p)[100];
    

    That is, it gives you just 1 pointer:

    ┌───────────┐
    │int(*)[100]│
    └───────────┘
    

    It should point at an array that contains 100 ints:

    ┌───────────┐
    │int(*)[100]│
    └─┃─────────┘
      ▼
    ┌───┬───┬───┬───┬───┬───┬┄
    │int│int│int│int│int│int│
    └───┴───┴───┴───┴───┴───┴┄
    

    You will get a pointer to an array when you use the address-of operator (&) on the name of an array. For example:

    int arr[100] = { /* some initial values */ };
    int (*p)[100] = &arr;
    

    Here, I've taken the address of the arr array, which gives me a pointer to that array. If you then want to access an element of the array, you have to dereference the pointer first: (*p)[3] will access element 3.

侧记:

请永远记住数组不是指针。正如我们刚刚所见,我们可以取一个数组的地址来获得指向它的指针,就像在C++中的任何其他(非临时)对象一样。数组和指针之间唯一的特殊联系是数组的名称可以隐式转换为指向数组第一个元素的指针。这意味着以下内容是有效的:

int arr[100] = { /* some initial values */ };
int* p = arr;

指针p将指向arr中的第一个元素。请注意,p不是指向数组的指针,而是指向数组元素的指针。

(还要注意,不存在数组类型的函数参数。如果您将int p[]写作函数参数,则编译器会将其转换为int*。)


6
优秀的 ASCII 艺术品 :-) - Joe
我也非常钦佩ASCII! - James Webster
另外,如果您能告诉我们如何绘制这些ASCII艺术,那将非常好。 - haccks
2
@haccks 方框绘图字符 - Joseph Mansfield
1
@kvv:指针是一个,可以根据需要生成一个变量。数组是一个,可以根据需要生成一组变量。因此,对于你的问题“何时使用指针?”,答案是“每当你需要将变量视为值时”。对于“何时使用数组?”的问题的答案是“每当你需要将一组变量视为一个值时”。 - Eric Lippert
显示剩余2条评论

19

听起来你可能需要了解螺旋法则

从变量开始,向右绕圈直到左边:

              +-------+
              | +--+  |             // So we have:
              | |  |  |                    p    // p     
          int * p  |  |                  * p    // p is a pointer
           ^  ^    |  |              int * p    // p is a pointer to an int
           |  +----+  |
           +----------+

下一个:
              +--------+
              | +--+   |         p       // p
              | |  V   |         p[100]  // p is an array of 100
          int * p[100] |       * p[100]  // p is an array of 100 pointers
           ^  ^    |   |   int * p[100]  // p is an array of 100 pointers to ints
           |  +----+   |
           +-----------+

最后,一个新的规则是:先处理括号里的内容。

                   +-----+            
                   | +-+ |    
                   | ^ | |         ( p)       // p
              int (* p)  [100];    (*p)       // p is a pointer
               ^   ^   | |         (*p)[100]  // p is a pointer to an array of 100
               |   +---+ |     int (*p)[100]  // p is a pointer to an array of 100 ints
               +---------+    

如果您在线或可以访问计算机,使用cdecl.org网站总是有用的,但能够离线阅读代码也很重要,这个规则将让您做到这一点。

2
这太棒了!我要打印出来。 - Fiddling Bits
1
以前从没听说过。+1。 - haccks

9
作为一名新手,C语言中类型的意义可能会让人感到棘手,即使对于专家也是如此。不用担心。
下面的代码有何区别?其他回答都很好,我没有打算与它们相矛盾。而是这里有另一个思考方式。我们需要定义三个事物:
- 变量是一个支持三个操作的东西。提取操作(fetch)获取变量并生成其当前值。提取操作没有符号;您只需使用该变量。存储操作(store)接受一个变量和一个值,并将该值存储在变量中。地址操作(address)接受一个变量并生成一个指针。 - 指针是一种支持一种操作的东西。解引用操作(dereference),写作前缀*pointer,接受一个指针并生成一个变量。(指针支持其他操作,例如算术和索引——这是一种算术形式——但我们不涉及这些。) - 数组是一种支持一种操作的东西。索引操作接受一个数组和一个整数,并生成一个变量。其语法是后缀:array[index]
现在我们来看看你的问题。声明的含义是什么呢?
int p;

意味着什么?意味着表达式 p 是一个类型为 int变量。请注意,这是一个变量,您可以将事物存储到 p 中。声明的含义是什么?

int *p;

这是什么意思?这意味着表达式*p是一个类型为int的变量。既然我们知道了这一点,我们就可以推断出p是什么。由于*p是一个解引用并产生一个变量,p必须是一个指向int的指针。那么声明是什么呢?
int *p[100];

这是什么意思?这意味着,如果i是一个从0到99的整数值,那么* p [i]表达式是一个int类型的变量。我们得到了一个变量,但我们既可以从指针中得到,也可以从数组中得到,因此我们必须弄清楚哪个是哪个。我们查看运算符优先级表并发现索引运算符比解引用运算符绑定更紧密。也就是说:
*p[i]

是同样的事情

*(p[i])

请记住,那个东西是一个类型为int的变量。括号中的内容被解引用以产生一个类型为int的变量,因此括号中的内容必须是指向int的指针。因此,

p[i]

这是一个int指针。可能是因为它是指向int类型的变量!所以p [i]是int类型的变量。由于这是一项索引操作,p必须是一个指向int的指针数组。

现在请您继续下一个。

int (*p)[100];

什么是


4

int *p; --> 这声明了一个指向整数类型的指针。

int *p[100]; --> 这声明了一个包含 100 个指向整数类型的指针的数组。

int (*p)[100]; --> 这声明了一个指向包含 100 个整数的数组的指针。

可以使用cdecl来翻译这些类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接