首页 文章

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

提问于
浏览
2

我正在使用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 回答

  • 7

    STRUCT_TYPEDEF array_var [] = some_struct.array2_var;

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

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

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

    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 );
    

    如果您不知道它需要多大,那么如果它需要在文件范围或者具有 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];
    

    如果它也只是一个指针,那么你将不得不以其他方式跟踪数组大小 .

    EDIT

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

    STRUCT_TYPEDEF *array_var = some_struct.array2_var;
    

    除非它是 sizeof 或一元 & 运算符的操作数,否则表达式为“N元素数组 T " will be converted ("衰变") to an expression of type "指向 T ”,表达式的值将是数组的第一个元素的地址 . 上面的代码完全等同于

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

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

  • 1

    这个 ...

    extern STRUCT_TYPEDEF array_var[];
    

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

    这个 ...

    STRUCT_TYPEDEF array_var[] = some_struct.array2_var;
    

    ...由于提供了初始化程序,声称是 array_var 的定义 . 但是, The initializer is not of the correct form for a variable of array type . 数组初始值设定项由一个或多个数组元素的逗号分隔序列组成,在强制花括号内( {} ) . 正如C不支持全数组赋值一样,它不支持数组值作为数组初始值设定项 .


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

    extern STRUCT_TYPEDEF *array_var;
    

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

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

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

    STRUCT_TYPEDEF *array_var = some_struct.array2_var;
    

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

    此外,这部分代码仅在像“array_var [0] .property = ...”这样的函数中引用,但这些函数都没有被调用过应用 .

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

    []和*我不知道有什么区别吗?

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

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

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

相关问题