我理解不支持成员分配数组,因此以下方法不起作用:
int num1[3] = {1,2,3};
int num2[3];
num2 = num1; // "error: invalid array assignment"
Run Code Online (Sandbox Code Playgroud)
我只是接受了这个事实,认为该语言的目的是提供一个开放式框架,并让用户决定如何实现诸如复制数组之类的东西.
但是,以下工作正常:
struct myStruct { int num[3]; };
struct myStruct struct1 = {{1,2,3}};
struct myStruct struct2;
struct2 = struct1;
Run Code Online (Sandbox Code Playgroud)
该数组num[3]是从其实例中成员分配struct1到其实例中的struct2.
为什么结构支持成员方式的数组,但一般情况下不支持?
编辑:Roger Pate 在结构中的线程std :: string中的注释- 复制/赋值问题?似乎指向答案的大致方向,但我不知道自己确认.
编辑2:许多出色的回应.我之所以选择Luther Blissett,是因为我对这种行为背后的哲学或历史原理很感兴趣,但James McNellis对相关规范文档的引用也很有用.
我并不想复制关于C不能返回数组的常见问题,而是要深入研究它.
我们不能这样做:
char f(void)[8] {
char ret;
// ...fill...
return ret;
}
int main(int argc, char ** argv) {
char obj_a[10];
obj_a = f();
}
Run Code Online (Sandbox Code Playgroud)
但我们可以这样做:
struct s { char arr[10]; };
struct s f(void) {
struct s ret;
// ...fill...
return ret;
}
int main(int argc, char ** argv) {
struct s obj_a;
obj_a = f();
}
Run Code Online (Sandbox Code Playgroud)
所以,我正在浏览由gcc -S生成的ASM代码,并且似乎正在使用堆栈,-x(%rbp)与任何其他C函数返回一样进行寻址.
直接返回数组有什么用?我的意思是,不是在优化或计算复杂性方面,而是在没有结构层的情况下这样做的实际能力方面.
额外数据:我在x64 Intel上使用Linux和gcc.
char arr[] = "Hello";
arr = arr + 1; // error occurs
Run Code Online (Sandbox Code Playgroud)
据我所知,具有数组类型的表达式将转换为指向数组初始元素的指针类型.因此,我期望arr = arr + 1(指向数组的第一个元素(arr)的指针成为指向数组的第二个元素的指针).为什么这不适用于C?
几乎每个读这篇文章的人都熟悉这三个关于C的关键事实:
[]与指针一样适用于指针.这三个事实绝对是C中数组和指针处理的核心.它们甚至不是三个独立的事实; 它们是一个中心概念的相互关联的方面.如果没有对这个概念的正确理解,就不可能正确地进行相当基本的C编程.
我今天的问题很简单,这个概念的名称是什么?
我以为我是老式的,但我总是把它称为"C中数组和指针之间的等价",或简称为"数组/指针等价".但我知道你几乎不能在SO上说出这些话; 他们几乎是禁忌.
这可能看起来像一个抽象或哲学问题,所以更具体地构建它,我正在寻找的是一个简单的名词或名词短语我可以在句子中使用"是的,由于_____,数组下标可以被认为是作为指针算术的语法糖",回答,比方说,这个问题.
(但是请注意,我不是在寻找这个问题的答案,也不是为了回答"'等价'这个词有什么问题?".是的,我知道,它会误导学习者想象数组和指针是某种方式同样.当我写这个FAQ列表条目时,我确实有这种困惑.)
这个问题源于 Eric Postpischil在另一个帖子中的评论。
我很难理解可变长度数组(VLA)作为函数参数的使用:
sizeof()下面的调用所示;即使完全有可能在堆栈上传递整个数组,就像定义 VLA 时在堆栈上创建一样。那么,如果 VLA 参数没有提供任何优势并且像指针的任何其他数组参数一样进行调整,那么为什么该语言允许使用 VLA 参数声明函数呢?如果语言不使用大小表达式(例如检查实际参数的大小)并且在函数内部无法获得大小表达式(仍然必须为此传递一个显式变量),为什么要对大小表达式进行求值?
为了更清楚地说明我感到困惑的地方,请考虑以下程序(此处为实时示例)。所有函数声明显然都是等效的。但正如 Eric 在另一个线程中指出的那样,函数声明中的参数大小表达式是在运行时评估的评估的。大小表达式不会被忽略。
我不清楚这会带来什么好处,因为大小及其评估没有影响(除了可能的副作用)。特别是,重复一遍,该信息不能被函数内部的代码使用。最明显的变化是在类似堆栈的结构上传递 VLA。毕竟,它们通常也在调用方的堆栈上。但与恒定长度的数组一样,类型在声明时已调整为指针 - 下面的所有声明都是等效的。尽管如此,仍会评估无用且被丢弃的数组大小表达式。
#include <stdio.h>
// Nothing to see here.
extern void ptr(int *arr);
// Identical to the above.
extern void ptr(int arr[]);
// Still identical. Is 1 evaluated? Who knows ;-).
extern void ptr(int arr[1]);
// Is printf evaluated when called? Yes.
// But the array is still …Run Code Online (Sandbox Code Playgroud) 这背后有什么历史或逻辑原因吗?
解释:当您将数组传递给 C 中的函数时,您实际上只传递了一个指向数组的指针。但是,当您传递结构时,您可以传递结构的副本或指针。
//this:
int function(int array[10])
// is equivalent to this:
int function(int *array)
//and they both pass a pointer
//but this:
int function(struct tag name)
//passes a struct by value, where as this:
int function(struct tag *name)
//passes a pointer to it.
Run Code Online (Sandbox Code Playgroud)
为什么会有差异?
在C:
当通过值(通过参数)将结构发送到函数时,会创建新的结构,因此更改函数内的结构将不会更改原始结构.
当数组通过值(通过参数)发送到函数时,会创建一个新指针,因此更改函数内的数组不会更改原始数组,而是更改函数内的数组值(因为我们有指向原始数组的指针)将更改原始数组中的值.
当带有数组字段的结构(通过参数)通过值发送到函数时,????? 是创建的,因此更改函数内的数组(指针)不会更改原始数组,更改数组值不会更改原始数组中的值.
第三点是否意味着结构的数组字段在被发送到函数时将被完全克隆?为什么不只是使用指针?规范对此有何规定?
我玩过的一段代码:
typedef struct {
int value;
int array[3]; /* initialized to 0 by default */
} Struct_t;
void foo(Struct_t structure)
{
printf("-- %p\n", structure.array); /* Pointer to local array */
structure.value = 1;
*structure.array = 1; /* Won't change the original array */
*(structure.array + 1) = 1; /* Won't change the original array */
structure.array[2] = …Run Code Online (Sandbox Code Playgroud) char str1[ ] = "Hello" ;
char str2[10] ;
char *s = "Hey" ;
char *q ;
str2 = str1 ; /* error */
q = s ; /* works */
Run Code Online (Sandbox Code Playgroud)
是C中的内置财产还是存在某种原因?如果无法分配数组,为什么还要分配包含数组的结构?
我对这段代码有几个问题(我不知道它是做什么的,它来自考试)。当数组像这样传递时,这意味着什么:nums[]?什么nums + 1意思?如果nums是一个数组,那么给它加1是什么意思?
int f(int nums[], int n){
if(n > 1) {
if(nums[0] < nums[1]) {
return 1 + f(nums + 1, n - 1);
}
else {
return f(nums + 1, n - 1);
}
}
else return 0;
}
Run Code Online (Sandbox Code Playgroud)