【问题标题】:How to use only part of an input array to a function?如何仅将输入数组的一部分用于函数?
【发布时间】:2016-07-24 11:36:15
【问题描述】:

我需要将一个恒定大小的数组传递给 C 中的函数,但只使用该数组的一部分。具体来说,下面的伪代码解释了我的情况:

void my_function(int arr_end,double arr[20]) {
    Create new array arr_new that contains elements 0 to arr_end or arr
    Use arr_new
}

到目前为止,我尝试执行以下操作:

void my_function(int arr_end,double arr[20]) {
    double arr_new[arr_end+1];
    int i;
    for(i=0;i<=arr_end;i++){
       arr_new[i] = arr[i];
    }
    // Now I can do what I want with arr_new
}

但我得到了错误:int arr_end expression must have a constant value .这是 Visual Studio Community 2015 中错误的屏幕截图:

我的问题是arr_end 不是恒定的(这意味着在不同的时间我想提取arr 的不同部分)。

我怎样才能实现我想要的(使arr_new 包含arr 的一部分)只使用基本代码而不使用malloc 或类似的东西?谢谢!

【问题讨论】:

  • Cannot reproduce. 你确定这个代码块抛出了错误吗?
  • 我认为数据类型有冲突,double arr_new 和 int arr_end
  • 您使用的是符合 C99 标准的编译器吗?
  • 呃,是的,Visual Studio isn't C99 compliant,所以不支持 VLA。只需将 VLA 替换为 mallocfree。查找如何执行此操作,然后在出现错误时发布您的新代码。
  • 好吧,您可以声明另一个固定大小的数组(似乎是最大值为 20)并仅使用其中的 arr_end 元素...

标签: c arrays memory dynamic


【解决方案1】:

首先在 my_function 参数中,您声明您正在接收大小为 20 (double arr[20]) 的数组,因为数组不能按值传递,它会被转换为 double* arr (see this)知道arr 有多少元素,所以你应该小心,否则你会得到一个segfault。推荐的方法是将double arr[20] 更改为double* arr 并为arr 的大小添加另一个参数。示例:

void my_function(const size_t arr_end, double* arr, const size_t arr_size) {
    ...
}

其次,您尝试将VLAsMSVC 一起使用,它仅支持C90 和我们在C99 上添加的VLA,因此您需要使用malloc 手动分配内存并使用@987654335 释放它@你用完的时候。

现在这里是修复的代码:

void my_function(size_t arr_end, double* arr, size_t arr_size) {
    double* arr_new = NULL;

    // Allocate enough memory to hold the array
    arr_new = malloc((arr_end + 1) * sizeof(double));

    // Copy arr elements to arr_new
    for(int i = 0; i <= arr_end; i++){
       arr_new[i] = arr[i];
    }

    // Now you can do what you want with arr_new

    // When you finished using it.
    free(arr_new);
}

【讨论】:

    【解决方案2】:

    旧的 c 版本不允许使用动态大小的数组,因此您可以:

    1. 更改编译标志以适合您并允许您进行编译,如果您使用的是 IDE,这可能取决于 IDE。

    2. 使用 malloc 或类似函数动态分配数组:

      void my_function(int arr_end,double arr[20]) { double *arr_new = malloc((arr_end+1) * sizeof(arr[0])); int i; for(i=0;i<=arr_end;i++){ // do whatever you need } }

    3. 在堆栈上分配一个大小为 20 的数组,并且只使用它的一部分(使用 for 循环),如下所示:

      void my_function(int arr_end,double arr[20]) { double arr_new[20]; int i; for(i=0;i<=arr_end;i++){ //do whatever you need } }

    如果您必须只发送您需要的部分,则方法 2 更可取。

    【讨论】:

    • 对于您的第三个解决方案,您如何仅使用数组的一部分?我需要将它作为一个整体传递给另一个不属于我的函数,那么我如何只将数组的一部分传递给该函数?
    • allocate an array of size 20 on the heap 你的意思是在堆栈上,对吧?如果大小已知,则将其放在堆上是没有意义的(在这种特定情况下,考虑到它的大小不足以粉碎 OP 的堆栈,只是为了那里的学究)
    • @space_voyager 该函数的签名是什么?或者更好的是,“我需要将其作为一个整体传递” 是什么意思?
    • @Bob__ 我的意思是我需要做类似another_function(arr_new) 的事情,其中​​another_function 是另一个功能。我不关心arr_new,我只需要将arr 的特定部分传递给another_function
    • @space_voyager 您知道数组在作为参数传递给函数时会衰减为指针,对吗?因此,通常,您必须传递数组的大小以避免越界访问,除非该大小被称为全局常量。
    【解决方案3】:

    据我所知,问题是当您创建动态数组时 唯一的方法是使用malloc 分配空间。然后你把它分配给一个数组 如double arr_new[arr_end+1];arr_end 只能是显式值,例如 123,而不是像 arr_end 这样的变量。应该是这样的double arr_new[5];

    【讨论】:

    • 这适用于旧版本的 C(以及所有版本的 C++)。但是 OP 可以在较新的版本下编译并获得使用这种可变长度数组的能力。请参阅 OP 的 cmets。
    • @underscore_d I don't think so.
    • @Downvoter “在 C 的新版本下编译”,即使用支持此类的编译器。 MS 不支持的列表如此之长,以至于我完全没有兴趣。但我指的是您对 OP 的评论,这有助于说明这一点。 (好名字,顺便说一句)
    • @underscore_d 你怎么知道 OP 可以“在新版本下编译”?
    • @Downvoter 我必须完全按照字面意思表达所有内容,并且对每个人的文字情况有深入的了解吗?显然,“可以”意味着这就是语言可以做的事情,如果它在逻辑上对你来说是可能的。你还有什么?让我们尝试一下子把所有的学究气都甩掉。
    【解决方案4】:

    显然,问题出在 Visual Studio 上。可变长度数组 (VLA) 的概念属于 C99 标准,而 Visual Studio 似乎只支持 C90。

    他们似乎确实有解决方法,但是你可以在这里找到它:https://msdn.microsoft.com/en-us/library/zb1574zs(v=vs.140).aspx

    【讨论】:

    • 那个页面没有意义。 “这是使用 VLA 的方法 [...] 目前不支持 VLA。”是哪个?
    • 它下面的代码部分,#pragma 行。实在帮不上忙。归咎于 MS 不支持更新的标准。
    • 是的,我确实阅读了整本书,但仍然没有意义。它首先说不支持 VLA,然后声明一个,然后才用它做一些与线程相关的东西,这似乎是正交的。我发现的所有其他问题都暗示它无法完成。因此,如果您发现其他情况,则值得扩展您的答案以解释此解决方法为何有效。目前,他们的例子看起来毫无关联。
    • 我同意,这没有任何意义。它更多的是掩盖缺乏支持的黑客行为。也许您可以切换到 GCC 来获得新功能?
    • 如果是黑客或掩饰,它是如何工作的?那里没有解释,我找不到任何相关的搜索结果,将 firstprivate 指令标识为使 VLA 工作的某种解决方法,所以我觉得有必要得出结论,该页面是不合理的。反正我不是OP,我已经用过GCC了,强烈推荐。
    【解决方案5】:

    使用动态分配。代码:

    void foo(int end, double arr[20]){
        double* newArr = malloc((end + 1) * sizeof(double));
        //now you can use newArr like a normal array
        //Copy like this
        for(int i = 0; i < end; i++){
            newArr[i] = arr[i];
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-29
      • 2011-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多