需要了解C中的一些指针

时间:2019-12-14 08:34:03

标签: c pointers

嗯,我有一个必须在学校使用的简单示例,但我不明白为什么必须使用指针以及它们在相同情况下的确切作用。

   int **create(int lines, int columns)
   {
   int **p, i;
   p = (int **) malloc(lines * sizeof(int *));
   for(i = 0; i < lines; i++)
      p[i] = (int *) malloc(columns * sizeof(int));   
   return p; 
   } 

我谷歌**是指向指针的指针。只需指向已存储变量地址的指针。但是为什么我应该这样做? 然后这两行代码看起来完全是随机的指针

p = (int **) malloc(lines * sizeof(int *));
p[i] = (int *) malloc(columns * sizeof(int));

我基本上理解指针指向变量或某些内容的地址,但不知道这里发生了什么。请有人可以向我解释一下。感谢您的宝贵时间。

3 个答案:

答案 0 :(得分:1)

指针也可以理解为数组。您可以使用malloc分配一些空间,并且可以使用[]运算符来设置项目,就像数组一样。

int* arr = (int*)malloc(sizeof(int)*3);
arr[1] = 5;
printf("%d", arr[1]); //output is 5

指针的指针可以理解为二维数组:您为指针分配空间 ,然后将每个指针分配为数组。

int** arr = (int**)malloc(sizeof(int*) * 3);
for (int i = 0; i < 3; i++) {
    arr[i] = (int*)malloc(sizeof(int) * 3); // each element is going to be an array of 3 integers
}
arr[2][2] = 4;
printf("%d", arr[2][2]); // 4

答案 1 :(得分:1)

此函数创建一个二维数组的矩阵。

数组是元素连续存储在内存中的序列。使用malloc,我们分配了可以用作数组的存储块。然后,我们持有一个指向元素块的指针。然后,我们可以使用符号a[i]来标识其地址存储在a中的数组的第i个元素。

表达式malloc(n * sizeof(int));n整数分配一个有空间的内存块。请注意,它返回一个指向整数的指针:int *

当我们创建一个二维数组时,每一行都是一个分配有上述指令的数组。 n替换为列数。

然后将所有行与一组数组捆绑在一起。请记住,数组的类型为int *。因此,一个数组的数组具有int *个值作为元素。则其类型为int **

代码中的第一个malloc分配一个数组,该数组将保存所有的行数组。这就是为什么其类型为int **的原因。其字节大小为lines的字节大小的int *倍。

for循环中,每一行都被实例化并分配给数组p的相应元素。

返回的二维数组的令人愉快的事情是,您随后可以通过表达式a[i][j]来标识其元素。


请注意,此代码有误。

for循环为for(i = 0; i < riadky; i++)riadky是未定义的变量。这不是正确的变量名。

现在,您希望能理解代码,是否可以找到正确的变量名来放置?您应该可以从我的解释中找到它。

答案 2 :(得分:1)

一些图片应该有帮助。

我们从对象p开始:

   int **
   +–––+
p: |   |
   +–––+

p的类型为int **,这意味着它可以存储类型为int *的对象的地址。

为简单起见,我们假设linescolumns均为2。因此,我们首先为两个int *类型的对象动态分配足够的空间,然后将其中第一个对象的地址存储到p中:

   int **        int *
   +–––+         +–––+
p: |   | ––––––> |   |
   +–––+         +–––+
                 |   |
                 +–––+

数组下标操作a[i]定义为*(a + i)-给定起始地址a,偏移量为i elements 个字节)从该地址 1 开始,然后取消引用结果 2 。因此,表达式p[0]引用第一个元素,p[1]引用第二个元素:

   int **        int *
   +–––+         +–––+
p: |   | ––––––> |   | p[0]
   +–––+         +–––+
                 |   | p[1]
                 +–––+

现在,对于每个p[i],我们为2个int对象分配足够的空间,并将每个集合的第一个地址分配给p[i]

   int **        int *          int
   +–––+         +–––+          +–––+
p: |   | ––––––> |   | p[0]-––> |   | p[0][0]
   +–––+         +–––+          +–––+
                 |   | p[1]–+   |   | p[0][1]
                 +–––+      |   +–––+
                            |
                            |   +–––+
                            +-> |   | p[1][0]
                                +–––+
                                |   | p[1][1]
                                +–––+

关于为什么需要使用多个间接级别(*****等)...

对于类型为E的任何对象T表达式 &E的计算结果为该对象的地址,并且该表达式的类型为{{ 1}}(指向T *的指针)。如果我们用指针类型为T来代替T,则P *的类型为&E。 IOW,保存另一个对象地址的对象类型必须比指向对象具有更高的间接级别。


  1. 指针算术根据对象而不是字节进行工作。如果P **的类型为p并指向int *对象,则int指向紧随其后的下一个p+1对象,无论该对象是否为2、4 ,或更多字节。
  2. “但是每个人都说数组不是指针,int是一个地址吗?”除非它是a或一元sizeof运算符的操作数,否则是用于初始化声明中的字符数组的字符串文字,类型为“ &的N元素数组的表达式将被转换(“衰变”)为类型为“指向{{1}的指针”的表达式}”,表达式的值将是第一个元素的地址。