简体   繁体   English

有关指针和数组的问题

[英]Questions about pointers and arrays

Sanity-check questions: 理智检查问题:

I did a bit of googling and discovered the correct way to return a one-dimensional integer array in C is 我做了一些谷歌搜索,发现在C中返回一维整数数组的正确方法是

int * function(args);
  1. If I did this, the function would return a pointer, right? 如果这样做,函数将返回一个指针,对吗? And if the return value is r, I could find the nth element of the array by typing r[n]? 如果返回值为r,则可以通过键入r [n]找到数组的第n个元素?

  2. If I had the function return the number "3", would that be interpreted as a pointer to the address "3?" 如果我让该函数返回数字“ 3”,那么该函数将被解释为指向地址“ 3”的指针吗?

  3. Say my function was something like 说我的功能有点像

     int * function(int * a); 

    Would this be a legal function body? 这将是一个法律职能机构吗?

     int * b; b = a; return b; 

    Are we allowed to just assign arrays to other arrays like that? 我们是否可以像这样将数组分配给其他数组?

  4. If pointers and arrays are actually the same thing, can I just declare a pointer without specifying the size of the array? 如果指针和数组实际上是同一回事,是否可以在不指定数组大小的情况下直接声明一个指针? I feel like 我感觉像

     int a[10]; 

    conveys more information than 传达的信息比

     int * a; 

    but aren't they both ways of declaring an array? 但是它们不是两种声明数组的方式吗? If I use the latter declaration, can I assign values to a[10000000]? 如果使用后一个声明,是否可以将值分配给a [10000000]?

Main question: 主要问题:

  1. How can I return a two-dimensional array in C? 如何在C中返回二维数组? I don't think I could just return a pointer to the start of the array, because I don't know what dimensions the array has. 我不认为我可以只返回指向数组开头的指针,因为我不知道数组的尺寸。

Thanks for all your help! 感谢你的帮助!

  1. Yes
  2. Yes but it would require a cast: return (int *)3; 是的,但是需要强制转换:return(int *)3;
  3. Yes but you are not assigning an array to another array, you are assigning a pointer to a pointer. 是的,但是您没有将一个数组分配给另一个数组,而是将一个指针分配给了一个指针。
  4. Pointers and arrays are not the same thing. 指针和数组不是一回事。 int a[10] reserves space for ten ints. int a [10]保留十个整数的空间。 int *a is an uninitialized variable pointing to who knows what. int * a是一个未初始化的变量,指向谁知道什么。 Accessing a[10000000] will most likely crash your program as you are trying to access memory you don't have access to or doesn't exist. 访问a [10000000]很有可能会导致程序崩溃,因为您正试图访问您无法访问或不存在的内存。
  5. To return a 2d array return a pointer-to-pointer: int ** f() {} 要返回2d数组,请返回指针到指针:int ** f(){}
  1. Yes; 是; array indexing is done in terms of pointer arithmetic: a[i] is defined as *(a + i) ; 数组索引是根据指针算法完成的: a[i]定义为*(a + i) we find the address of the i 'th element after a and dereference the result. 我们找到的地址, i以后“th元素a和解引用的结果。 So a could be declared as either a pointer or an array. 因此a可以将a声明为指针或数组。

  2. It would be interpreted as an address, yes (most likely an invalid address). 它将被解释为一个地址,是的(很可能是无效地址)。 You would need to cast the literal 3 as a pointer, because values of type int and int * are not compatible. 您需要将文字3为指针,因为intint *类型的值不兼容。

  3. Yes, it would be legal. 是的,这是合法的。 Pointless, but legal. 没有意义,但是合法。

  4. Pointers and arrays are not the same thing; 指针和数组不是一回事。 in most circumstances, an expression of array type will be converted ("decay") to an expression of pointer type and its value will be the address of the first element of the array. 在大多数情况下,数组类型的表达式将被转换(“衰减”)为指针类型的表达式,其值将成为数组第一个元素的地址。 Declaring a pointer by itself is not sufficient, because unless you initialize it to point to a block of memory (either the result of a malloc call or another array) its value will be indeterminate , and may not point to valid memory. 仅仅声明一个指针是不够的,因为除非将其初始化为指向内存块( malloc调用的结果或另一个数组的结果),否则其值将是不确定的 ,并且可能不会指向有效内存。

  5. You really don't want to return arrays; 您真的不想返回数组; remember that an array expression is converted to a pointer expression, so you're returning the address of the first element. 请记住,数组表达式将转换为指针表达式,因此您将返回第一个元素的地址。 However, when the function exits, that array no longer exists and the pointer value is no longer valid. 但是,当函数退出时,该数组不再存在,并且指针值不再有效。 It's better to pass the array you want to modify as an argument to the function, such as 最好将要修改的数组作为参数传递给函数,例如

    void foo (int *a, size_t asize) { size_t i; void foo(int * a,size_t asize){size_t i; for (i = 0; i < asize; i++) a[i] = some_value(); 对于(i = 0; i <asize; i ++)a [i] = some_value(); } }

Pointers contain no metadata about the number of elements they point to, so you must pass that as a separate parameter. 指针不包含有关它们指向的元素数量的元数据,因此您必须将其作为单独的参数传递。

For a 2D array, you'd do something like 对于2D阵列,您将执行以下操作

void foo(size_t rows, size_t columns, int (*a)[columns])
{
   size_t i, j;
   for (i = 0; i < rows; i++)
     for (j = 0; j < columns; j++)
        a[i][j] = some_value;
}

This assumes you're using a C99 compiler or a C2011 compiler that supports variable length arrays; 假设您使用的是支持可变长度数组的C99编译器或C2011编译器; otherwise the number of columns must be a constant expression (ie, known at compile time). 否则,列数必须是一个常量表达式(即,在编译时已知)。

These answers certainly call for a bit more depth. 这些答案当然需要更多的深度。 The better you understand pointers, the less bad code you will write. 您对指针的了解越多,编写的错误代码就越少。

An array and a pointer are not the same, EXCEPT when they are. 数组和指针不一样,除了它们不同。 Off the top of my head: 从我的头顶上:

int a[2][2] = { 1, 2, 3, 4 }; int (* p)[2] = a; ASSERT (p[1][1] == a[1][1]);

Array "a" functions exactly the same way as pointer "p." 数组“ a”的功能与指针“ p”的功能完全相同。 And the compiler knows just as much from each, specifically an address, and how to calculate indexed addresses. 而且编译器从每个对象(尤其是地址)中了解同样多的知识,以及如何计算索引的地址。 But note that array a can't take on new values at run time, whereas p can. 但请注意,数组a在运行时不能采用新值,而p可以。 So the "pointer" aspect of a is gone by the time the program runs, and only the array is left. 因此,a的“指针”方面在程序运行时就消失了,只剩下了数组。 Conversely, p itself is only a pointer, it can point to anything or nothing at run time. 相反,p本身只是一个指针,它可以在运行时指向任何东西或什么都没有。

Note that the syntax for the pointer declaration is complicated. 注意,指针声明的语法很复杂。 (That is why I came to stackoverflow in the first place today.) But the need is simple. (这就是为什么我今天首先来到stackoverflow的原因。)但是需求很简单。 You need to tell the compiler how to calculate addresses for elements past the first column. 您需要告诉编译器如何计算第一列之后的元素的地址。 (I'm using "column" for the rightmost index.) In this case, we might assume it needs to increment the address ((2*1) + 1) to index [1][1]. (在最右边的索引中使用“列”。)在这种情况下,我们可能假设它需要将地址((2 * 1)+ 1)递增到索引[1] [1]。

However, there are a couple of more things the compiler knows (hopefully), that you might not. 但是,编译器(希望)还有另外两件事,您可能还不知道。

The compiler knows two things: 1) whether the elements are stored sequentially in memory, and 2) whether there really are additional arrays of pointers, or just one pointer/address to the start of the array. 编译器知道两件事:1)是否将元素顺序存储在内存中,以及2)是否确实存在额外的指针数组,或者仅是指向数组开头的一个指针/地址。

In general, a compile time array is stored sequentially, regardless of dimension(s), with no extra pointers. 通常,编译时间数组是顺序存储的,而与维无关,没有额外的指针。 But to be sure, check the compiler documentation. 但是可以肯定的是,请查看编译器文档。 Thus if the compiler allows you to index a[0][2] it is actually a[1][0], etc. A run time array is however you make it. 因此,如果编译器允许您为a [0] [2]编制索引,则实际上它是a [1] [0],依此类推。不过,您可以通过运行时数组来建立索引。 You can make one dimensional arrays of whatever length you choose, and put their addresses into other arrays, also of whatever length you choose. 您可以选择任意长度的一维数组,并将它们的地址放入任意长度的其他数组中。

And, of course, one reason to muck with any of these is because you are choosing from using run time multiplies, or shifts, or pointer dereferences to index the array. 而且,当然,其中任何一个都不可行的原因是因为您选择使用运行时乘法,移位或指针取消引用来索引数组。 If pointer dereferences are the cheapest, you might need to make arrays of pointers so there is no need to do arithmetic to calculate row addresses. 如果指针取消引用是最便宜的,则可能需要创建指针数组,因此无需进行算术运算即可计算行地址。 One downside is it requires memory to store the addtional pointers. 缺点之一是它需要内存来存储附加指针。 And note that if the column length is a power of two, the address can be calculated with a shift instead of a multiply. 并请注意,如果列长度是2的幂,则可以通过移位而不是乘法来计算地址。 So this might be a good reason to pad the length up--and the compiler could, at least theoretically, do this without telling you! 因此,这可能是增加长度的一个很好的理由-编译器至少在理论上可以做到这一点而无需告诉您! And it might depend on whether you select optimization for speed or space. 这可能取决于您是否选择速度或空间优化。

Any architecture that is described as "modern" and "powerful" probably does multiplies as fast as dereferences, and these issues go away completely--except for whether your code is correct. 任何被描述为“现代”和“强大”的体系结构都可能确实会像取消引用一样快地成倍增长,并且这些问题将完全消失-除了您的代码是否正确之外。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM