麻烦的理解传递多维数组给函数时传递什么元素 [英] trouble understanding what elements are passed when passing multidimensional arrays to functions

查看:92
本文介绍了麻烦的理解传递多维数组给函数时传递什么元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我读的地方,下面的阵列可以被传递到以这样的方式以下功能,如以下所示,但是我不理解正在准确传递给函数数组中的哪些元素。结果
这些是阵列

I read somewhere that the following arrays can be passed to the following functions in such a manner, as shown below, however I do not understand what elements within the array are being passed exactly to the function.
These are the arrays

int array[NROWS][NCOLUMNS];
int **array1;
int **array2;
int *array3;
int (*array4)[NCOLUMNS];

和这些的功能是:

f1(int a[][NCOLUMNS], int m, int n);
f2(int *aryp, int nrows, int ncolumns);
f3(int **pp, int m, int n);

这我从读出的网站提到,我们可以通过以下阵列以下功能以这样的方式:

The website that I read from mentions that we may pass the following arrays to the following functions in such a manner :

f2(&array[0][0], NROWS, NCOLUMNS);
f2(*array2, nrows, ncolumns);
f2(array3, nrows, ncolumns);
f2(*array4, nrows, NCOLUMNS);
f3(array1, nrows, ncolumns);
f3(array2, nrows, ncolumns);

不是数组1 数组2 指针数组?所以,当你将它们传递到 F3 ,所有的指针获得通过?而关于数组2 传递给时,F2 F2 有在正式的参数正常的指针,但数组2 是一个指针数组,所以你会怎么访问各个行和传递指针数组 F2时,列?而路过时会怎么ü访问单独的行和列 array4 这是一个指向一系列的一维数组的运作 F2

Isn't array1 and array2 an array of pointers? So when you pass them to the f3, all the pointers get passed? And about array2 when passed to f2, f2 has a normal pointer in formal arguments, but array2 is an array of pointers, so how would you access individual rows and columns when passing array of pointers to f2? And how would u access individual rows and columns when passing array4 which is a pointer to a series of 1D arrays to function f2?

推荐答案

您可以percieve什么在C数组并不总是在语言的概念来阵列。

What you can percieve as arrays in C are not always arrays in terms of language concepts.

C是从70年代的语言。这是非常接近机实现其更抽象的后代进行比较。所以,你必须执行到如果你想了解以后如何混淆性相似的语法元素。

C is an language from the 70's. It's very close to machine implementation compared with its more abstract offsprings. So you must take implementation into account if you want to understand what lies beyond confusingly similar syntactic elements.

这两个指针和数组可以通过访问 (方)括号标记

Both pointers and arrays can be accessed through (square) bracket notation.

括号标记是undoubtely有用的,但它是所有罪恶的根源,只要指针和数组之间的混乱而言。

Bracket notation is undoubtely useful, but it is the root of all evil as far as confusions between pointers and arrays is concerned.

F [I] 将工作为指针和数组为好,虽然基本的机制会有所不同,因为我们将拭目以待。

f[i] will "work" for pointers and arrays as well, although the underlying mechanisms will differ, as we will see.

让我们先从变量声明。

浮动*˚F只是告诉符号˚F总有一天会引用数目不详的彩车的编译器。

float * f simply tells the compiler that the symbol f will someday reference an unknown number of floats.

˚F未初始化。它是由你来决定实际数据将会和设置˚F来指向它们。

f is not initialized. It is up to you to decide where the actual data will be and to set f to point to them.

请记住,当你添加/一。减去值的指针,单位是尖型的大小。

Keep in mind that when you add/substract a value to a pointer, the unit is the size of the pointed type.

float * f;
float * f3 = f+3; // internal value: f + 3 * sizeof (float)

// these two statements are identical
*f3 = 1;
*(f+3) = 1;

由于写 *(F + I)当你想从一个指针引用连续数据是尴尬,在括号标记可以使用

Since writing *(f+i) is awkward when you want to reference contiguous data from a pointer, the bracket notation can be used:

f[3] = 1; // equivalent to *(f+3) = 1;

不管使用的符号的,f的地址[3]计算这样:

Regardless of the notation used, the address of f[3] is computed like that:

@f [ 3 ] = F + 3 *的sizeof(浮动)

您可以考虑˚F功能的作为(动态)阵列,但是为C看到它,它仍然是一个的指针,通过语法使它看起来像一个数组引用。

You could consider f functionally as a (dynamic) array, but as C sees it, it's still a pointer, referenced through a syntax that makes it look like an array.

浮法F [10] 还告诉编译器˚F将引用一些彩车,但它也

float f[10] still tells the compiler that f will reference some floats, but it also


  • 花车分配的请求数量的适当位置

    • 堆栈如果˚F上是一个自动的局部变量

    • 在静态数据(又名BSS)如果˚F是一个全局或静态变量

    • allocates the requested number of floats at the appropriate location
      • on the stack if f is an automatic local variable
      • in the static data (aka BSS) if f is a global or static variable

      尽管数组创建语法可能会造成混乱,数组将始终在编译时已知固定大小。

      Even though array creation syntax might be confusing, an array will always have a fixed size known at compile time.

      例如,浮法F [] = {2,4,8} 声明长度为3的数组,相当于浮法F [ 3 ] = {2,4,8} 。尺寸可以方便省略:长度反映初始化符的数量不强迫程序员重复explicitey

      For instance, float f[] = {2,4,8} declares an array of length 3, equivalent to float f[3] = {2,4,8}. The dimension can be omitted for convenience: the length mirrors the number of initializers without forcing the programmer to repeat it explicitey.

      不幸的是, [] 标记也可以指的指针的其他一些情况下(稍后更多)。

      Unfortunately, the [] notation can also refer to pointers in some other circumstances (more on that later).

      括号标记是访问数组内容的最自然的方式。

      Bracket notation is the most natural way of accessing array contents.

      当你引用一个数组,编译器的知道的它是一个数组。然后,它可以访问基于在阵列第一元件上的数据,这样的:

      When you reference an array, the compiler knows it's an array. It can then access the data based on the array first element, like that:

      @f [ 3 ] = F + 3 *的sizeof(浮动)

      在一维数组的情况下(但在这种情况下,只有!)中,可以看到,该地址计算是完全一样的指针。

      In case of single-dimensional arrays (but in that case only!), you can see that the address computation is exactly the same as for a pointer.

      由于数组也被认为是(常量)指针,可以使用数组初始化指针,认为反显然是假的(因为数组是的的指针,因此其值不能更改)。​​

      Since an array is also considered a (constant) pointer, you can use an array to initialize a pointer, thought the reverse is obviously false (since an array is a constant pointer and as such its value cannot be changed).

      void test (void)
      {
          float* f1;
          float  f2[10];
          float  f3[];         // <-- compiler error : dimension not known
          float  f4[] = {5,7}; // creates float f4[2] with f4[0]=5 and f4[1]=7
      
          f1[3] = 1234; // <--- write to a random memory location. You're in trouble
          f2[3] = 5678; // write into the space reserved by the compiler
      
          // obtain 10 floats from the heap and set f1 to point to them
          f1 = (float *) calloc (10, sizeof(float));
          f1[3] = 1234; // write into the space reserved by you
      
          // make f1 an alias of f2 (f1 will point to the same data as f2)
          f1 = f2;              // f2 is a constant pointer to the array data
          printf ("%g", f1[3]); // will print "5678", as set through f2
      
          // f2 cannot be changed
          f2 = f1; // <-- compiler error : incompatible types ‘float[10]’ / ‘float *’
      }
      

      走向多维

      让我们的示例扩展到二维的情况下:

      Going multidimensional

      let's extend our example to the two-dimensional case:

      float    f2[3][10]; // 2d array of floats
      float ** f1;        // pointer to pointer to float
      
      f1 = f2; // <-- the compiler should not allow that, but it does!
      
      f2[2][5] = 1234;           // set some array value
      printf ("%g\n", f2[2][5]); // no problem accessing it
      
      printf ("%g\n",f1[2][5]);  // bang you're dead
      

      让我们来看看这里发生了什么。

      let's see what happened here

      在声明浮动F2 [3] [10] ,编译器分配的30彩车需要作为一个连续的块。第10彩车重新present F [0],未来十年F [1],等等。

      when you declare float f2[3][10], the compiler allocates the 30 required floats as a contiguous block. The first 10 floats represent f[0], the next ten f[1], etc.

      当你写 F2 [ 2 ] [ 5 ] ,编译器仍然知道˚F阵列,所以它可以计算所需的浮动这样的有效地址:

      When you write f2[2][5], the compiler still knows f is an array, so it can compute the effective address of the required float like this:

      @ F2 [ 2 ] [ 5 ] = F +( 2 * 10 + 5 )* sizeof的(浮动)

      您也可以访问的指针通过多个支架,只要指针的参考水平的适当数量:

      You can also access pointers through multiple brackets, provided the pointer has the proper number of reference levels:

      在引用指针时,编译器只是简单的应用指针算术陆续:

      When referencing the pointer, the compiler simply applies pointer arithmetics in succession:

      float h = f1[2][5];
      

      相当于:

      float * g = f1[2]; // equivalent to g = *(f1+2)
      float   h = g[5];  // equivalent to h = *(g +5)
      

      F1 [ 2 ] [ 5 ] 是由编译器为 *(*(F1 + 2 )+ 5
      最终的地址将被计算是这样的:

      f1[2][5] is handled by the compiler as *(*(f1+2)+5). The final address will be computed like this:

      @ F1 [ 2 ] [ 5 ] = *(F + 2 * sizeof的(浮动*))+ 5 *的sizeof(浮动)

      超越同括号标记的谎言两个非常不同的实现。

      Beyond the same bracket notation lie two very different implementations.

      显然,通过 F1 试图访问 F2 数据时,结果将是灾难性的。

      Clearly, when trying to access f2 data through f1, the results will be catastrophic.

      编译器会从 3号浮F2 [2] ,认为这是一个指针,加20到并尝试引用结果地址。

      The compiler will get the 3rd float from f2[2], consider it as a pointer, add 20 to that and try to reference the resulting address.

      如果您通过这种错误地初始化指针写一些值后,认为自己是幸运的,如果你得到一个访问冲突,而不是默默破坏内存一些随机的四个字节。

      If you write some value through this kind of wrongly initialized pointer, consider yourself lucky if you get an access violation instead of silently corrupting some random four bytes of memory.

      不幸的是,即使底层的数据结构不能正常访问,除非编译器知道 F2 是一个数组, F2 还是视为一个常量浮法** 指针

      Unfortunately, even though the underlying data structure cannot be accessed properly unless the compiler is aware that f2 is an array, f2 is still considered a constant float** pointer.

      在一个理想的世界,它不应该,但在C(唉!),它是。

      In an ideal world it should not, but in C (alas!), it is.

      这意味着您可以将指针赋值给一个数组的没有编译器抱怨它,即使结果是没有意义的。

      It means you can assign a pointer to an array without the compiler complaining about it, even though the result makes no sense.

      这两个数组和指针可以作为参数传递给函数。

      Both arrays and pointers can be passed as parameters to functions.

      不过,为避免这种灾难性misinter pretations作为在previous例如,你必须让编译器知道你是传递给函数是一个数组或一个指针。

      However, to avoid such catastrophic misinterpretations as in the previous example, you must let the compiler know whether what you are passing to the function is an array or a pointer.

      在这里,由于编译器在考虑一个数组作为一个常量指针,你将被允许做愚蠢的事情像声明数组并将它传递给一个函数像一个指针。

      Here again, due to the compiler considering an array as a constant pointer, you will be allowed to do silly things like declaring an array and passing it to a function like a pointer.

      要更糟糕的是,函数参数声明的语法允许的方式,使数组和指针之间的混淆,甚至更有可能使用括号。

      To make things worse, the syntax of function parameter declaration allows to use brackets in a way that makes confusion between arrays and pointers even more likely.

      void f (float f1[]);
      

      也正是作为处理

      void f (float * f1);
      

      尽管变量声明

      float f1[];
      

      将产生,而不是将其视为声明浮动*˚F的替代方法错误。

      您可以说, [] 标记允许指定的指针,但只在函数的参数即可。

      You could say that the [] notation is allowed to designate pointers, but only in function parameters.

      为什么它不能被允许作为变量的声明可能是开放的辩论(除其他事项外,这将是暧昧与浮法F [] = {...} 初始化数组声明语法),但最终结果是,功能参数介绍decalaration的符号,增加了混乱的另一层。

      Why it has not be allowed as a variable declaration might be open to debate (among other things, it would be ambiguous with the float f[] = { ... } initialized array declaration syntax), but the net result is that function parameter decalaration introduce a notation that adds another layer of confusion.

      例如,著名的的argv 参数可以宣布任何奇怪的方式:

      For instance, the famous argv parameter can be declared any odd way:

      int main (int argc, char ** argv)
      int main (int argc, char * argv[])
      int main (int argc, char argv[][])
      

      在另一方面,提供您知道指针和数组之间的区别,空括号是一定程度上比指针符号更加方便,尤其是在这种情况下:

      On the other hand, provided you are fully aware of the difference between pointers and arrays, the empty brackets are somewhat more convenient than the pointer notation, especially in that case:

      void fun (float f[][10]); // pointer to arrays of 10 floats
      

      相当于指针语法强迫你使用括号:

      the equivalent pointer syntax forces you to use brackets:

      void fun (float (* f)[10]);
      

      该声明这样的变量时,你无法避免:

      which you can't avoid when declaring such a variable:

      float (* f)[10]; // pointer to array of 10 floats
      float f[][10];   // <-- compiler error : array dimension not known
      

      结论

      至于函数原型而言,你有语法变体之间的选择,但如果你传递给函数变量不匹配的原型,它都将结束在流泪。

      Conclusion

      As far as function prototypes are concerned, you have the choice between syntactic variants, but if the variable you pass to the function doesn't match the prototype, it will all end in tears.

      float      ** var1;           // pointer to pointer to float
      float       * var2[10];       // array of pointers to float
      float      (* var3)[10];      // pointer to array of floats (mind the brackets!)
      float         var4[10][10];   // array of arrays of floats (2d array of floats)
      
      // using empty brackets notation
      void fun1 (float f[  ][  ]);
      void fun2 (float f[10][  ]);
      void fun3 (float f[  ][10]);
      void fun4 (float f[10][10]);
      
      // using same syntax as for variables declaration
      void fun1 (float ** f);
      void fun2 (float * f[10]);
      void fun3 (float (* f)[10]); // <-- [] notation (arguably) easier to read
      void fun4 (float f[10][10]); // must always use square brackets in that case
      
      // even more choice for multiple level pointers
      void fun1 (float * f[]);
      
      // any funI (varJ) call with I != J will end up in tears
      

      的意见的最后一个字

      这当然是个人喜好的问题,但我会建议使用的typedef 作为变得有点更抽象的一种方式,并限制使用C语法的古怪到最低限度。

      A final word of advice

      It is of course a matter of personal taste, but I would recomend the use of typedef as a way of getting a bit more abstraction and limit the use of C syntactic oddities to a minimum.

      // type definition
      typedef float (* tWeirdElement)[10];
      typedef tWeirdElement (* tWeirdo)[10]; // pointer to arrays of 10 pointers
                                             // to arrays of 10 floats 
      
      // variable declaration
      tWeirdo weirdo;
      
      // parameter declaration
      void do_some_weird_things (tWeirdo weirdo);
      

      这篇关于麻烦的理解传递多维数组给函数时传递什么元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆