如何将指针传递给数组而不会衰减,并使用'引用'在野蛮人的功能?

时间:2016-08-09 19:07:06

标签: c pebble-watch pebble-sdk

我已经阅读了很多关于将数组传递给函数的讨论。它们似乎是为那些精通C语言的人写的。我是一个野蛮人,但还不熟悉C语言。

从我在其他讨论中读到的内容,应该可以传递一个没有指针衰减的数组。但是,我需要帮助实现这一点。

请给我一个简洁的例子,说明如何将数组作为指针的指针传递,并确定它在传递函数内的大小。

如果在函数中更改了数组,我希望更改数组的源。我想尽量减少额外的内存分配。 并且,如果可能的话,我想在功能中确定数组的大小。

此代码无需通过即可。

// this works
j = sizeof(hourLongs)/sizeof(hourLongs[0]);
i = 0; while (now > hourLongs[i] && i < j){i++;}  
hour = --i; 

这样可行,但无法在函数中调整数组的大小。

hour = compareToLongs(&now, hourLongs, (int)(sizeof(hourLongs)/sizeof(hourLongs[0])) ); 

// long *, long * , int -> int 
// compare time to array of times.
static int compareToLongs(long * time, long * timeList_pointer, int size){
  i = 0; while (*time> (timeList_pointer)[i] && i < size){i++;}  
  return --i;
}

我想以一种允许我在函数中找到它的大小的方式传递数组。像下面的东西,减去我的错误。

hour = compareToLongs(&now, &hourLongs); 

// long *, (long (*) [])*  -> int 
// compare time to array of times.
static int compareToLongs(long * time, long ** timeList_pointer){
  int size = (int)(sizeof(*timeList_pointer)/sizeof(*timeList_pointer[0]));
  i = 0; while (*time> (i < size && *timeList_pointer)[i]){i++;}
  free(size);  
  return --i;
}

编辑:hourLongs是一个长整数数组。

编辑:关于标题,我使用了“&#39; reference&#39;用白话,以便像我这样的其他野蛮人可以找到问题。

编辑:我真的在寻找一种在函数中调整整数数组的方法。

sizeof(array)

给sizeof()一些地址,允许确定大小。这是我想传递给我的函数的地址。

我有没有理由不能将传递给sizeof()的内容传递给我的函数?

编辑:因为sizeof()的操作表明可以在没有&#34;指针衰减的情况下传递数组&#34;。 user529758在this discussion

中给出了三个示例
in C99 there are three fundamental cases, namely:
1. when it's the argument of the & (address-of) operator.
2. when it's the argument of the sizeof operator.
3. When it's a string literal of type char [N + 1] or a wide string literal of type wchar_t [N + 1] (N is the length of the string) which is used to initialize an array, as in char str[] = "foo"; or wchar_t wstr[] = L"foo";.

我应该尝试使用&amp; array。

3 个答案:

答案 0 :(得分:3)

C中,您无法在被调用函数中找到数组的大小。调用者函数必须传递一个说明数组大小的参数。

让我们看一些例子,看看为什么这是不可能的。

首先在调用函数时,您将尝试将数组作为参数传递。但是,请注意,当您将数组作为参数传递时,它会自动依赖于指向其元素数据类型的指针。这将阻止called函数使用sizeof运算符计算数组的大小。

例如,

int main(void)
{
    int arr_a[2] = {22, 33};
    int arr_b[5] = {6, 7, 8, 9, 10};

    foo(arr_a); // Here arr_a decays to an `int *`
    foo(arr_b); // Here arr_b decays to an `int *` too

    return 0;
}

void foo(int *arr)
{
    sizeof(arr); 
    /* Here sizeof(arr) will always give the size of 
     * an `int *` which maybe 4 or 8 bytes depending
     * on platform. It does not matter weather arr_a
     * or arr_b was passed from main.   
     * And because sizeof(arr) always gives the sameresult, 
     * we cannot use sizeof(arr)/sizeof(arr[0]) to calculate 
     * the size of array that was passed.
     */

     /* This value will always be the same, 
      * regardless of what was passed */
     sizeof(arr)/sizeof(arr[0]); 

}

另外,请注意:

void foo(int arr[]) { ... }

相当于:

void foo(int *arr) { ... }

编译器会默默地将int arr[]更改为int *arr。因此,将int arr[]作为参数不会有任何区别。

下一步,您可能会想到传递数组的地址(通过执行&arr_name)。不过请注意,&arr_namepointer to array (of some DEFINITE size),与pointer to pointer to underlying datatype 不同。这次你做这样的事情。

void foo(void) {
    int arr_a[2] = {22, 33};
    int arr_b[3] = {7, 8, 9};
     bar(&arr_a); // Note here that type of `&arr_a`  is `int (*)[2]`,
                  // i.e. a `pointer to int array of 2 elements`, which is
                  // different from a `pionter to pointer to int`

     bar(&arr_b); // Note here that type of `&arr_b`  is `int (*)[3]`,
                  // i.e. a `pointer to int array of 3 elements`, which is
                  // different from a `int (*)[2]`, 
                  // i.e a `pointer to int array of 2 elements`
                  // Note that this will give ERROR. See comments in bar()
    return 0;
}

void bar(int (*arr)[2]) {
     /* 
      * The caller of this function can ONLY pass int arrays with
      * 2 elements. Caller CANNOT pass int array with 3 elemens, or
      * 1 element, or 5 element.
      * This means you ALWAYS KNOW the size of arrays being passed,
      * and although you can calculate the size by doing
      * sizeof(*arr)/sizeof(*arr[0]); 
      * There is no point in calculating it - you alreay know the size 
      */
}

所以,基本上你甚至不能通过pointer to the array传递&array_name来解决这个问题,因为你需要不同的函数来接受不同大小的数组。例如,void bar_2(int (*arr)[2]) {...}接受pointer to array of 2 integersvoid bar_3(int (*arr)[3]) {...}接受pointer to array of 3 integers。此外,计算这些函数的大小是没有意义的,因为你已经知道了。

最后,您将尝试传递pointer to pointer to the underlying datatype。所以你做了类似的事情:

void foo() {
    int arr_a[2] = {22, 33};
    int arr_b[5] = {6, 7, 8, 9, 10};
    int *ptr;
    ptr = &arr_a[0];
    bar(&ptr); // Passing pointer to pointer to int (int **)
    ptr = &arr_b[0];
    bar(&ptr); // Passing pointer to pointer to int (int **)
}

void bar(int **pptr) {
    sizeof(*pptr);
    /* This will always be the same. 
     * i.e. the size of an integer pointer 
     * So here again you cannot use 
     * sizeof(*pptr)/sizeof((*pptr)[0]) to calculate the size
     * as it will always give the same result */

     sizeof(*pptr)/sizeof((*pptr)[0]) // Always same, no matter what was
                                      // passed by the caller
}

您看到传递pointer to pointer to underlying datatype也无法解决此问题。

所以,你看,无论你做什么,你都无法通过在被调用函数中使用sizeof()来找到数组的大小。只有在调用者传递此信息时,被调用的函数才能知道数组的大小。

作为旁注,您的代码中存在问题。当你在做什么

 i = 0; while (now > hourLongs[i] && i < j){i++;}  // AND
 i = 0; while (*time> (timeList_pointer)[i] && i < size){i++;} 

while循环中您的条件顺序应该是相反的。它应该是

 i = 0; while ( i < j && now > hourLongs[i]){i++;}  // AND
 i = 0; while (i < size && *time> (timeList_pointer)[i]){i++;} 

这是因为,您必须首先检查i是否在数组的范围内,然后才评估hourLongs[i](timeList_pointer)[i]

答案 1 :(得分:1)

正如其他人所说,你不能将一个数组传递给一个函数并获得它的大小,因为当传递给一个函数时,数组如何衰减到指向第一个元素的指针。所以你需要将数组及其大小传递给你的函数。

有一种将数组传递给函数的迂回方式,因此您可以获得它的大小,但它只适用于固定大小的数组。

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

void test1(int (*a)[10])
{
    int i;
    printf("size=%zu\n",sizeof(*a));
    for (i=0;i<sizeof(*a)/sizeof((*a)[0]);i++) {
        printf("%d\n",(*a)[i]);
    }
}

int main()
{
    int a[10] = {1,2,3,4,5,6,7,8,9,10};
    test1(&a);
    return 0;
}

上面的代码允许您将指针传递给固定大小的数组。然后,您可以取消引用该指针以将元素数量设为sizeof(*a)/sizeof((*a)[0])

但是,您只能将int [10]数组传递给此函数。您无法传递任何其他大小的数组。因此,在这种情况下,您只需将上述表达式替换为10,因为已知大小。

答案 2 :(得分:0)

当你声明一个数组时,c在后台做的事情基本上只是为你想要的大小分配足够的内存然后给你一个指针。当你说

int arr[20];

实际发生的是c为20个整数分配足够的内存并给你一个名为arr的指针(有一些区别,但为了简单起见我用这种方式解释),所以如果一个函数的签名需要一个指向一个int,你可以把它传给它。

void foo(int *);
foo(arr);      */ works */

这是有效的,所以不需要使用指向指针的指针,虽然你必须指定大小,因为ac数组基本上只是一个指向某个内存的指针,所以你可以接收大小为参数或标记数组的最后一个元素的方式类似于标记字符串结尾的方式(使用空终止符)。 当你使用[]运算符时,c只是偏移指针并取消引用它,所以这两个语句是等价的(一个不太可读)

arr[10] = somevalue;
*(arr+10) = somevalue;
// In general, arr[n] is equivalent to *(arr+n).

希望这有助于你更好地理解它,即使我的解释有点过分了。