代码之家  ›  专栏  ›  技术社区  ›  jkeys

在C中传递一个数组作为参数++

  •  13
  • jkeys  · 技术社区  · 17 年前

    //merge sort first attempt
    
    #include <iostream>
    
    #include <algorithm>
    
    #include <vector>
    
    int mergeSort(int[]);
    int main() {
        int originalarray[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 10 };
        mergeSort(originalarray[]);
    }
    
    int mergeSort(int[] originalarray) {
        int num = (sizeof(originalarray) / sizeof(int));
        std::vector < int > original(num);
    
        if (num > 2) {
            return num;
        }
    
        // Fill the array using the elements of originalarray
        // This is just for demonstration, normally original will be a parameter,
        // so you won't be filling it up with anything.
        std::copy(originalarray, originalarray + num, original.begin());
    
        // Create farray and sarray of the appropriate size
        std::vector < int > farray(num / 2);
        std::vector < int > sarray(num - farray.size());
    
        // Fill those using elements from original
        std::copy(original.begin(), original.begin() + farray.size(), farray.begin());
        std::copy(original.begin() + farray.size(), original.end(), sarray.begin());
    
        mergeSort(farray);
        mergeSort(sarray);
    }
    

    请注意,这个mergeSort函数不起作用,因为我还没有弄清楚如何合并它们(这是我的任务)。在处理这个问题之前,我想先对两个向量进行排序,但我无法编译它,因为我需要传递一个数组作为参数。我不理解指针,所以如果这是解决方案,我的借口是无知。我现在正在学习编程,以C++为第一语言,对该语言的特性只有基本的了解。谢谢你的帮助。

    7 回复  |  直到 7 年前
        1
  •  33
  •   Community Mohan Dere    6 年前

    为了稍微扩展一下,请记住C++数组是 精确地 C数组。所以,你所拥有的只是一段内存的地址,它声称(没有保证)是一组东西。

    更新

    好吧,我们再扩大一点。

    C(因此C++)并没有真正的“数组”。它只有地址和指针。所以当你把某个东西做成“数组”时,真正发生的是你告诉编译器某个变量代表一个地址。

    在C中区分a和b是有用的 声明 和一个 定义 在声明中,你只是给某物一个名称和一个类型;在定义中,您实际上是在分配空间。

    所以,如果我们从定义一个数组开始,比如

    int ar[100];
    

    这意味着我们告诉编译器我们需要100的空间 int 的,我们希望将其全部分配到一个块中,我们将使用该名称 ar 为了它 sizeof 运算符给出了类型或对象使用的字节数,因此我们的数组 ar 将占用100 sizeof(int) 字节。在大多数机器上,这将是400字节,但它因机器而异。

    如果我们定义一个变量

    int * ar_p;   // using '_p' as a reminder this is a pointer
    

    我们正在为一个包含地址的变量定义空间。它的大小将是 sizeof(int*) ,通常为4或8,但在某些机器上,它可能是2到16之间的任何值,在一些你不太可能很快遇到的机器上。

    这 名字 数组的 ar 编译器将该名称转换为地址,因此我们可以用

    ar_p = ar ;     // THIS WORKS
    

    现在,为了方便起见,我们假设我们的数组 ar

    这个名字 ar 做 不 为其分配任何空间;它就像一个常数,一个数字。所以,你不能颠倒这个任务

    ar = ar_p ;     // THIS WON'T WORK
    

    出于同样的原因,你不能说

    1000 = ar_p ;   // THIS WON'T WORK EITHER
    

    即,你不能改变1000的值。(在FORTRAN的早期版本中,由于复杂的原因,这个技巧是可行的。这是一个错误。除非你尝试调试一个“2”值为3的程序,否则你永远活不下去。)

    C中的数组总是从零开始的,也就是说,第一个索引总是零。任何其他索引都只是使用索引计算的地址。所以, ar[0] 只是地址1000加上0字节的偏移量,即1000。 ar[1] 是1000加1倍的大小 整数 ,所以 下一个 int结束。事实上,在C中总是如此。

    这被称为 数组引用 .

    当我们使用语法时 *ar_p 我们告诉编译器从中包含的地址获取内容 ar_p . `.

    这叫做 引用指针 .

    如果我们说

    ar_p = ar;
    

    然后 *ar_p 和 ar[0] 指的是同一件事。

    当我们说 ar[0] ar . ar[1] 地址是1吗 整数 ,或4个字节,来自 ar 因此, *(ar_p+3) 指的是与 ar[3] (我们需要括号,因为我们想先在地址上加3,然后再查看内容。 *ar_p+3 将获得指向的内容 ap_p 首先,然后再加3。

    问题是,C不知道或不太关心数组到底有多大 ar[365] ,编译器将愉快地生成代码来查找单元格1000+(365 size(int) ).如果它在你的数组中,那很好,但如果它只是随机内存,那也没关系。C不在乎。

    (记住C来自电话公司。“我们不在乎;我们不必。我们是电话公司。”)

    所以,现在,我们知道了一些规则,我把它们搬到了这里。阅读“as”相当于“or”与“相同”。

    你可以依靠的是:

    • foo(TYPE t[]) foo(TYPE * t)

    由于C不知道指针和数组之间的区别,您可以声明其中之一。当你定义一个函数时,你可以写

    void foo(int[] ar){
    

    或

    void foo(int* ar){
    

    并获得完全相同的效果。

    • t[i] *(t+i)

    这是上面。无论你在哪里写作 ar[i] ,您可以用以下内容替换它 *(ar+i) (实际上有一个奇怪的副作用打破了这一点,但作为初学者,你不会遇到它。)

    • 哪里 TYPE *t (t+i) 将等于地址 t 加 i*sizeof(TYPE)

    上面也解释了这一点。当你索引数组时,比如 ar[42] ,这意味着你想把42号从起始地址改过来。所以,如果你正在使用 整数 ,那么你需要移动超过42次,无论移动的幅度有多大 整数 是,也就是说 size(int) .

    现在,这都是C,由于C++被定义为“一种”C,因此它也适用于C++。除了

    • 除非 TYPE operator[] 和 operator* .

    在C++中,你可以决定定义一个新类型,它的行为就像任何其他类型一样,但你可以改变语言做特定事情的方式。所以,程序员 能 决定用他们自己设计的东西“重载”(即替换)数组引用和指针解引用运算符的默认行为。作为一个初学者,你不应该很快遇到这种情况,但你应该意识到这一点。

        2
  •  19
  •   Mehrdad Afshari    17 年前

    你不应该使用 sizeof(originalarray)/sizeof(int) 就像那样。它只适用于静态声明的数组(大小在编译时已知)。你必须把尺寸和它一起传递。你为什么不做一个 vector 退出数组并传递它?

    旁注: 根据经验,一定要注意 sizeof 将在编译时翻译。因此,它无法知道作为参数传递的数组的大小。

        3
  •  4
  •   Assaf Lavie    17 年前

    我看到你包括 <vector> 。我建议你放弃使用数组,只使用 vector 类。您可以看到如何使用STL容器的示例,例如 向量 here .

        4
  •  2
  •   dirkgently    17 年前
    • 当你将数组传递给函数时,它们会衰减为指向数组第一个元素的指针,尽管有符号。那么,你的 sizeof 没有按预期工作。

    • 当你传入一个数组时,最好传入数组大小,这样你就知道在哪里停止了。将其添加为附加参数。

        5
  •  0
  •   Ye Liu    17 年前

    除了上述所有答案外,您可能还想查看Q&关于c-faq.com的数组: http://c-faq.com/aryptr/index.html

        6
  •  0
  •   user3458 user3458    17 年前

    不幸的是,在C或C++中很难做到你想做的事情。你可以像这样传递一个固定大小的数组:

    int mergeSort(int originalarray[20])
    {
        // do something
    }
    

    但是,数组的大小不是由数字定义的,而是由初始化列表中的元素数量定义的。

    在你的情况下,要做的事情(即使这真的是一件错误的事情)是分两步做:

    int originalarray[] = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
    const size_t arraySize = sizeof originalarray / sizeof originalarray[0];
    int mergeSort(int array[arraySize])
    {
        // do something
    }
    

    太糟糕了,它不会做你需要做的事情:将数组传递给这样的函数会复制数组,排序的目的是更改原始数组。

    事实上,如果不理解“指针”的概念,你就无法走得更远。

    你需要开发的功能应该是这样的:

    int originalarray[] = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
    const size_t arraySize = sizeof originalarray / sizeof originalarray[0];
    
    int mergeSort(int *array, const size_t size)
    {
        // do something
    }
    
    mergeSort(&(originalArray[0]), arraySize);
    

    换句话说,你传递一个指向第一个元素的指针和元素的数量。

    或者,您可以处理向量。Vector将相同的两个东西(指向第一个元素的指针和大小)封装在一个称为“对象”的实体中。此外,它还为您管理内存,因此您可以根据需要扩展元素的数量。这就是C++的方式。遗憾的是,你无法像初始化数组那样,使用{…}来初始化向量。

        7
  •  0
  •   Snazzer    17 年前

    看起来你同时使用了动态分配数组和向量,而我认为只使用std::vector就足够了。

    首先,将输入数组更改为std::vector,并用输入数据填充它。

    int main()
    {
       std::vector<int> originalarray;
       for (int data = 1; data <= 10; data++)
       {
          originalarray.push_back(data);
       }
       mergeSort(originaldata);
    }
    

    现在,重要的是声明你的mergesort函数来引用std::vector。

    int mergeSort(std::vector<int>& originalarray)
    {
       // The rest of your code, note that now you are passing 
       // in your array for sorting, so you can continue with your code to split
       // the vector into farray and sarray
    
       // then call sort on your halves.
       mergeSort(farray);
       mergeSort(sarray);
    
       // I'm guessing at this point you'd write code to combine your farray sarray, and
       // put it back into originalarray...don't forget to clear original array first!
    }
    

    只是一个注释,看起来你没有进行就地排序,所以预计你的排序需要一段时间,因为你要复制大量数据。