c – ‘struct(*)[]’和’struct * []’之间有什么区别?
我正在玩指针,指针数组和数组.
我创建了一个名为Fraction的结构,并尝试将一个Fraction数组传递给一个带有Fraction指针数组的函数.我收到错误: Error 1 error C2664: 'void display(Fraction *[],int)' : cannot convert argument 1 from 'Fraction (*)[10]' to 'Fraction *[]' 我知道这不起作用,但你对这些中的每一个都称之为什么?分数(*)[]和分数* [].例如:int []是一个整数数组,int *是一个整数指针.除了围绕*的括号外,上面的代码看起来与我相同. 我不需要修复这个错误我只是想了解这两个看似相似的结构之间的差异. 解决方法
分数* []是分数*(指针数组)的数组.分数(*)[]是指向Fraction [](指向数组的指针)的指针.不同之处在于括号将“指针”与Fraction隔离开,因为否则两者会相互绑定并为您提供与预期不同的类型.
机械地,a *或a&更愿意绑定到一个类型名称而不是被隔离并代表整个事物,所以你必须使用括号将它与元素类型隔离开来.声明函数指针时也是如此:int *(int,int)是一个接受两个int并返回一个int *的函数,而int(*)(int,int)是一个指向一个带两个整数的函数的指针.返回一个int. 考虑this简单程序: #include <iostream> #include <typeinfo> struct Type {}; // 1: Array of Type*. void func(Type *arr [3]) { std::cout << "Type* array.n" << typeid(arr).name() << "nn"; } // 2: Array of Type&. // Illegal. // void func(Type &arr [3]) { // std::cout << "Type& array.n" // << typeid(arr).name() << "nn"; // } // 3: Pointer to array of Type. void func(Type (*arr) [3]) { std::cout << "Pointer to Type array.n" << typeid(arr).name() << "nn"; } // 4: Reference to array of Type. void func(Type (&arr) [3]) { std::cout << "Reference to Type array.n" << typeid(arr).name() << "nn"; } int main() { // Array of Type. Type t_arr[3] = {}; // Array of Type*. Type* tp_arr[3] = { &t_arr[0],&t_arr[1],&t_arr[2] }; // Array of Type&. // Illegal. // Type& tr_arr[3] = { t_arr[0],t_arr[1],t_arr[2] }; std::cout << "Type[3]: " << typeid(t_arr).name() << "nn"; func(t_arr); // Calls #4. func(&t_arr); // Calls #3. func(tp_arr); // Calls #1. } 根据所使用的编译器,它将输出arr的mangled或unmangled类型,输出显示所有三种都是不同的类型: // MSVC: Type[3]: struct Type [3] Reference to Type array. struct Type [3] Pointer to Type array. struct Type (*)[3] Type* array. struct Type * * // GCC: Type[3]: A3_4Type Reference to Type array. A3_4Type Pointer to Type array. PA3_4Type Type* array. PP4Type 如果你不习惯它,这种语法有点难以理解,并且可能有点容易输入错误,因此如果你需要使用它,建立一个类型别名可能是个好主意. // Array. typedef Type Type_arr_t[3]; // Pointer. typedef Type (*Type_arr_ptr_t)[3]; // Reference. typedef Type (&Type_arr_ref_t)[3]; // ... // Without typedefs. Type arr [3]; Type (*arr_p)[3] = &arr; Type (&arr_r)[3] = arr; // With typedefs. Type_arr_t arr2; Type_arr_ptr_t arr2_p = &arr2; Type_arr_ref_t arr2_r = arr2; 这在声明返回指针或对数组的引用的函数时非常有用,因为它们看起来很傻而没有typedef,并且很容易出错和/或忘记语法. typedef Type (*Type_arr_ptr_t)[3]; typedef Type (&Type_arr_ref_t)[3]; // Without typedefs. Type (*return_ptr())[3]; Type (&return_ref())[3]; // With typedefs. Type_arr_ptr_t return_ptr_2(); Type_arr_ref_t return_ref_2(); 有关如何解析此类内容的更多信息,请参阅clockwise spiral rule. 注意:当数组作为函数参数传递值时,以及在许多其他情况下(特别是在任何不期望数组但指针是的情况下),类型和维度信息都会丢失,并且它是隐式的转换为指向数组第一个元素的指针;这被称为数组decaying into a pointer.这在上面的func(Type * [3])中进行了演示,其中编译器采用Type * [3]的参数类型,Type *的数组,并将其替换为Type **,指向Type *的指针; [3]丢失了,用一个简单的*代替,因为函数可以指针而不是数组.调用func()时,数组会因此而衰减.因此,以下签名被视为相同,参数在所有三个中都是Type **. void func(Type*[3]); void func(Type*[] ); // Dimension isn't needed,since it'll be replaced anyways. void func(Type** ); 这样做是因为它比尝试按值传递整个数组更有效(它只需要传递一个指针,它很容易适合单个寄存器,而不是试图将整个数据加载到内存中),并且因为编码数组键入函数的参数列表将删除函数关于它可以采用的数组大小的任何灵活性(如果函数采用类型[3],那么你不能传递类型[4]或类型[ 2]).因此,编译器将使用Type *静默替换Type [N]或Type [],从而导致数组在传递时衰减.通过专门获取指向数组的指针或引用可以避免这种情况;虽然这与让数组衰减一样有效(前者因为它仍然只传递指针,后者因为大多数编译器使用指针实现引用),但它会失去灵活性(这就是为什么它通常与模板配对,这会恢复灵活性,没有删除任何严格性). // Will take any pointer to a Type array,and replace N with the number of elements. // Compiler will generate a distinct version of `func()` for each unique N. template<size_t N> void func(Type (*)[N]); // Will take any reference to a Type array,and replace N with the number of elements. // Compiler will generate a distinct version of `func()` for each unique N. template<size_t N> void func(Type (&)[N]); 但是请注意,C没有丰富的模板,因此任何旨在使用这两种语言的代码都应该使用传递“size”参数和数组的C语言,或者专门为一定大小的数组;前者更灵活,而后者则非常有用,如果您永远不需要采用任何其他大小的数组. void func1(Type *arr,size_t sz); void func2(Type (*arr)[3]); 另请注意,有阵列won’t decay into a pointer的情况. // Example array. Type arr[3]; // Function parameter. void func(Type arr[3]); void func(Type (*arr)[3]); void func(Type (&arr)[3]); // Function template parameter. template<typename T> void temp(T t); // Class template parameter. template<typename T> struct S { typedef T type; }; // Specialised class template parameter. template<typename T> struct S2; template<typename T,size_t Sz> struct S2<T[Sz]> { typedef T type[Sz]; }; func(arr); // C: arr decays into Type*. // C++: arr either binds to a Type(&)[3],or decays into Type*. // If both are available,causes error due to ambiguous function call. func(&arr); // C/C++: No decay,&arr is Type(*)[3]. sizeof(arr); // C/C++: No decay,evaluates to (sizeof(Type) * 3). alignof(arr); // C/C++: No decay,evaluates to alignof(Type). decltype(arr); // C++: No decay,evaluates to Type[3]. typeid(arr); // C++: No decay,evaluates to a std::type_info for Type[3]. for (Type& t : arr); // C++: No decay,ranged-based for accepts arrays. temp(arr); // C++: arr decays to Type* during function template deduction. temp<Type[3]>(arr); // C++: No decay,deduction isn't required. // For class templates,deduction isn't performed,so array types used as template parameters // don't decay. S<Type[3]>::type; // C++: No decay,type is Type[3]. S2<Type[3]>::type; // C++: No decay,type is Type[3]. // String literals are arrays,too. decltype("Hello."); // C++: No decay,evaluates to const char[7]. char c_arr[] = "Hello."; // C/C++: No decay,c_arr is a local array,of type char[7],// containing copy of "Hello." const char* c_ptr = "Hello."; // C/C++: const char[7] "Hello." is stored in read-only // memory,and ptr points to it. // There may be other cases in which arrays don't decay,which I'm currently not aware of. 因此,简而言之,虽然Type [3]是一个数组类型,而Fraction * [5]是一个数组类型,但有些情况下,两个声明将被静默替换为Type *或Fraction **分别由编译器和类型和维度信息将由此丢失;这种损失称为阵列衰减或阵列到指针衰减. 谢谢你去juanchopanza提醒我提到数组到指针的衰变. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |