array [] vs pointer * - 为什么第一个代码在C中失败?

时间:2016-05-19 17:11:48

标签: c arrays pointers keil c51

我正在使用Keil C51编译器来编程8051微控制器。由于某些原因,我的代码没有运行 - 我设法追踪错误,但我仍然难以理解它。为什么第一个代码与另一个代码相比是错误的?值得注意的是,编译器没有抛出任何错误,代码甚至没有在微控制器上启动。

错误的代码:

file1.h

extern STRUCT_TYPEDEF array_var[];

file2.c中

// Global variable initialization
STRUCT_TYPEDEF array_var[] = some_struct.array2_var;

将这些更改为:

file1.h

extern STRUCT_TYPEDEF *array_var;

file2.c中

// Global variable initialization
STRUCT_TYPEDEF *array_var = &some_struct.array2_var[0];

它开始工作了。

此外,这部分代码仅在“array_var [0] .property = ...”等函数中引用,但这些函数都没有从应用程序中调用过。

some_struct变量在另一个模块中声明。

为什么它会像那样? []和*之间有什么区别我不知道吗?

EDIT1: 据说指针和数组是不同的东西......但是,“[]”语法与“*”的区别是什么?我认为只要方括号为空(例如函数参数),编译器就会将其转换为指针。我还认为提供一个数组会导致给我第一个元素的地址。

现在,每个人都在说指针和数组是不同的 - 但我找不到任何关于它们究竟有什么不同的信息。当我将数组作为rvalue而不是指向其第一个元素的指针时,编译器如何看待它?

2 个答案:

答案 0 :(得分:7)

  

STRUCT_TYPEDEF array_var[] = some_struct.array2_var;

不是在声明中初始化数组的有效方法。数组初始值设定项必须是大括号括起来的初始值设定项列表,例如

T arr[] = { init1, init2, init3 };

您不能使用另一个数组 1 初始化数组,也不能以这种方式将一个数组分配给另一个数组:

T foo[] = { /* list of initializers */ }
T bar[] = foo; // not allowed
T bar[N];
...
bar = foo; // also not allowed

如果您要将some_struct.array2_var的内容复制到array_var,则必须使用memcpy之类的库函数:

memcpy( array_var, some_struct.array2_var, sizeof some_struct.array2_var );

您还必须声明array_var的大小;如果你想使用它,你就不能完整。如果你提前知道它需要多大,那很简单:

STRUCT_TYPEDEF array_var[SIZE];
...
mempcy( array_var, some_struct.array2_var );

如果你没有提前知道它需要多大,那么你要么必须将它声明为一个可变长度数组(它赢得了&#39 ;如果它需要在文件范围内或具有static存储持续时间,则工作,或者您可以动态声明内存:

STRUCT_TYPEDEF *array_var = NULL;
...
array_var = malloc( sizeof some_struct.array2_var );
if ( array_var )
{
  memcpy( array_var, some_struct.array2_var, sizeof some_struct.array2_var );
}

这都假设some_struct.array2_var是一个声明为

的数组
STRUCT_TYPEDEF array2_var[SIZE]; 

如果它只是一个指针,那么你必须以其他方式跟踪数组大小。

修改

如果您希望array_var只是指向some_struct.array2_var的第一个元素,那么您可以执行以下操作:

STRUCT_TYPEDEF *array_var = some_struct.array2_var;

除非它是sizeof或一元&运算符的操作数,否则表达式类型为" N元素数组T"将被转换("衰减")到类型为&#34的表达式;指向T"的指针,并且表达式的值将是第一个元素的地址。阵列。上面的代码完全等同于

STRUCT_TYPEDEF *array_var = &some_struct.array2_var[0];

<小时/>

  1. 字符串文字除外,例如char message[] = "Hello";;字符串文字"Hello"是一个数组表达式,但该语言将其视为一种特殊情况。

答案 1 :(得分:1)

这......

extern STRUCT_TYPEDEF array_var[];

...是一个未知大小和外部链接的数组的声明。由于未指定大小,因此该声明会使array_var留下&#34;不完整类型&#34 ;;除非其类型由同一翻译单元中的另一个声明完成,否则会阻止对该变量的某些使用。例如,它不能是sizeof运算符的操作数。

这......

STRUCT_TYPEDEF array_var[] = some_struct.array2_var;

...由于提供了初始化程序,声称是array_var的定义。 然而,初始化程序的数组类型变量的格式不正确。数组初始值设定项由一个或多个数组元素的逗号分隔序列组成,在强制大括号({})内。正如C不支持整数组赋值一样,它也不支持数组值作为数组初始化器。

相比之下,这......

extern STRUCT_TYPEDEF *array_var;

...是带有外部链接的指针的声明。它有一个完整的类型。这......

STRUCT_TYPEDEF *array_var = &some_struct.array2_var[0];

...是变量的有效定义,带有合适的初始化程序。因为数组值在这个上下文中衰减为指针,就像大多数(但不是全部)其他的一样,它等同于:

STRUCT_TYPEDEF *array_var = some_struct.array2_var;

在将其与原始代码进行比较时,必须要了解尽管它们具有紧密关联,但指针和数组是完全不同的类型。

  

此外,这部分代码仅在&#34; array_var [0] .property = ...&#34;等函数中引用,但这些函数都没有从应用程序中调用过。

是否正常访问变量与编译器是否愿意接受代码无关。

  

[]和*之间是否存在一些差异?我不知道?

显然是这样,因为这个问题似乎假设没有区别。

这两种形式可以互换使用,用于声明功能参数。在该上下文中,都将参数声明为指针。这是一种符号和代码清晰度方便,因为作为函数参数出现的数组值会衰减到指针。你永远不能将数组作为函数参数传递 - 当参数指定数组时,会传递指针。

然而,如上所述,两种形式等同于声明普通变量。