简体   繁体   English

ANSI C-初始化数组

[英]ANSI C - initializing an array

What I was always doing is: 我一直在做的是:

int arr[] = {2, 3, 4};

and it always worked. 并且一直有效。

I've heard of a better way to initialize new array, using the pointer: 我听说过使用指针初始化新数组的更好方法:

int *arr = {2, 3, 4};

However, it doesn't work in any IDE, it throws some errors like int differs in levels of indirection from int , or too many initializers . 但是,它在任何IDE中均不起作用,它会引发一些错误,例如int differs in levels of indirection from int ,或者too many initializers How should I do this? 我应该怎么做?

int arr[] = {2, 3, 4};

is just fine, and completely correct. 很好,而且完全正确。 No need to change. 无需更改。

That initialization seems to work for me, on gcc, but not correctly. 在gcc上,该初始化似乎对我有用,但不正确。

int *arr = {2, 3, 4}; //weird behaviour, stores first value `2` as read-only

int arr[] = {2, 3, 4}; //array decl

The former isn't a correct way to initialize an array. 前者不是初始化数组的正确方法。

For a char* , it makes more sense 对于char * ,这更有意义

char* arr = "abcde"; //Pointer to a read-only char array in memory

char[] arr = "abcde"; //Normal char array

The difference: 区别:

The former is written to the Rodata (constant, read-only data) section of the assembly, while the latter, resides in the read/write Data-Segment . 前者被写入到程序集的Rodata (常量,只读数据)部分,而后者则位于读/写Data-Segment中 Any attempt to change the former, might result in a segmentation-fault . 尝试更改前者可能会导致segmentation-fault


The places where the values are stored are different. 值的存储位置不同。

char* arr = "abcde";
arr[1] = 'f'; //(undefined behavior)

char[] arr2 = "abcde";
arr2[1] = 'f'; //no issue

If you want to "initialize an array", you have to initialize an array , not a pointer. 如果要“初始化数组”,则必须初始化一个数组 ,而不是一个指针。

Anyway, in C99 compound literals can be used and a pointer can be initialized as 无论如何,在C99中可以使用复合文字,并且可以将指针初始化为

int *arr = (int []) {2, 3, 4};

which is close to what you were trying to do. 这与您尝试执行的操作很接近。 Although the term "ANSI C" is often used to refer to C89/90, where this feature is not available. 尽管术语“ ANSI C”通常用于指代C89 / 90,但该功能不可用。

There's nothing "better" about this approach. 这种方法没有“更好”的选择。 It just gives you a pointer instead of an array, so it is really a question of what you need. 它只是给您一个指针而不是一个数组,因此这实际上是您需要什么的问题。

Why would the second version be better than the first? 为什么第二个版本会比第一个版本好?

The first version at least is explicit: you define an int array, with the given elements. 至少第一个版本是显式的:您使用给定的元素定义一个int数组。 Let the compiler determine how to do this optimally. 让编译器确定如何最佳地执行此操作。

Going from your comment to Evan Li ("string is also kind of an array, and it is initialized with a pointer. Thus, arrays should be also initialized this way."). 从您的评论转到Evan Li(“字符串也是一种数组,并且使用指针对其进行了初始化。因此,数组也应以这种方式进行初始化。”)。 If the instructor actually told you this, I'd seriously think about finding a new instructor, because he's confused about things. 如果讲师确实告诉过您,我会认真考虑寻找新的讲师,因为他对事情感到困惑。

A string literal is an array expression; 字符串文字是数组表达式。 the literal "Hello" is a 6-element array of char ( const char in C++). 文字“ Hello”是char的6个元素的数组(在C ++中为const char )。 String literals are stored in such a way that their memory is allocated over the lifetime of the program; 字符串文字的存储方式是在程序的生命周期内分配它们的内存。 this memory may or may not be read-only, depending on the platform. 该内存可能是只读的,也可能不是只读的,具体取决于平台。 The behavior on attempting to modify the contents of a string literal is undefined , meaning you may get a segfault, or the string may get modified, or something else happens. 尝试修改字符串文字内容的行为是未定义的 ,这意味着您可能会遇到段错误,或者可能会修改字符串,或者发生其他情况。

When an array expression appears in a context other than as an operand to the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, then the type of the expression is converted ("decays") from "N-element array of T " to "pointer to T ", and the value of the expression is the address of the first element of the array. 当数组表达式出现在上下文中而不是作为sizeof或一元&运算符的操作数时,或者在声明中使用字符串常量来初始化另一个数组时,表达式的类型将被转换(“ decays”) “ T N个元素数组”到“指向T指针”,表达式的值是数组的第一个元素的地址。

That's why you can write something like 这就是为什么你可以写像

char *foo = "This is a test";

The string literal "This is a test" is an array expression of type "15-element array of char "; 字符串文字"This is a test"是类型为“ 15个元素的char数组"This is a test"的数组表达式; since it isn't the operand of the sizeof or & operators, and isn't being used to initialize another array of char , the type of the expression becomes "pointer to char ", and the address of the first character is assigned to foo . 因为它不是sizeof&运算符的操作数,并且不用于初始化另一个char数组,所以表达式的类型变为“ char指针”,并且第一个字符的地址分配给foo By comparison, 通过对比,

char foo[] = "This is a test";

declares foo as an array of char ; foo声明为char 数组 the size is computed from the size of the initializer string (15 characters), and the contents of the string literal are copied to foo . 从初始化程序字符串的大小(15个字符)计算出大小,并将字符串文字的内容复制到foo

A string is an array expression; 字符串是数组表达式; a brace-enclosed list of values is not . 大括号括起来的值列表不是

int *foo = {1, 2, 3};

won't create a 3-element array of int and assign the address of the first element to foo ; 不会创建一个3元素的int数组,并将第一个元素的地址分配给foo instead, this should be a constraint violation if I'm reading this right: 相反,如果我正在阅读权限,则应该违反约束:

6.7.9 Initialization 6.7.9初始化

Constraints 约束条件

2 No initializer shall attempt to provide a value for an object not contained within the entity being initialized. 2初始化程序不得尝试为未包含在正在初始化的实体内的对象提供值。

As of C99, you can use what are known as compound literals , like so: 从C99开始,您可以使用所谓的复合文字 ,如下所示:

int *foo = (int []) {1, 2, 3};

The cast-expression (int []) is required. 强制转换表达式(int [])是必需的。 This does create a new 3-element array of int and assigns the address of the first element to foo . 这确实创建了一个新的3元素int数组,并将第一个元素的地址分配给foo Unlike string literals, compound literals like this only exist for the duration of the enclosing block 1 ; 与字符串文字不同,此类复合文字仅在封闭块1的持续时间内存在; IOW, if you did something like IOW,如果您做了类似的事情

int *foo = NULL;
if (condition())
{
  foo = (int []){1, 2, 3};
  // do stuff
}
// do more stuff

the anonymous array object pointed to by foo only exists within the if block; foo指向的匿名数组对象仅存在于if块中; once the if block exits, the array no longer exists, and the value of foo is no longer valid. 一旦if块退出,该数组将不再存在,并且foo的值不再有效。


1. If the compound literal is defined at file scope (outside of any function), then it has static duration and exists for the lifetime of the program. 1.如果复合文字在文件范围内(在任何函数之外)定义,则它具有static持续时间,并且在程序的生存期内存在。

int arr[] = {2, 3, 4}; int arr [] = {2,3,4}; is ok. 还可以

If you want to use pointer, you will have to allocate memory with for example malloc. 如果要使用指针,则必须使用例如malloc分配内存。 Something like that : 像这样:

  int *arr = malloc(sizeof(int)*4);

  arr[0]=1;
  arr[1]=2;
  arr[2]=3;
  arr[3]=4;

  //display
  printf("%d %d %d %d\n",arr[0],arr[1],arr[2],arr[3]);

  free(arr);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM