6.7. InitializationThis is a printer-friendly version of a page on the GBdirect web site. The original page may be found at https://publications.gbdirect.co.uk/c_book/chapter6/initialization.html. Now that we have seen all of the data types supported by C, we can look at the subject of initialization. C allows ordinary variables, structures, unions and arrays to be given initial values in their definitions. Old C had some strange rules about this, reflecting an unwillingness by compiler writers to work too hard. The Standard has rationalized this, and now it is possible to initialize things as and when you want. There are basically two sorts of initialization: at compile time, and at run time. Which one you get depends on the storage duration of the thing being initialized. Objects with static duration are declared either outside
functions, or inside them with the keyword Any other object has automatic duration, and can only be initialized at run time. The two categories are mutually exclusive. Although they are related, storage duration and linkage (see Chapter 4 [https://publications.gbdirect.co.uk/c_book/chapter4/]) are different and should not be confused. Compile-time initialization can only be done using constant expressions; run-time initialization can be done using any expression at all. The Old C restriction, that only simple variables (not arrays, structures or unions) could be initialized at run time, has been lifted. 6.7.1. Constant expressionsThere are a number of places where constant expressions must be used. The definition of what constitutes a constant expression is relatively simple. A constant expression is evaluated by the compiler, not at
run-time. It may be used anywhere that a constant may be used. Unless it is
part of the operand of If real numbers are evaluated at compile-time, then the Standard insists that they are evaluated with at least as much precision and range as will be used at run-time. A more restricted form, called the integral constant
expression exists. This has integral type and only involves operands
that are integer constants, enumeration constants, character constants,
The arithmetic constant expression is like the integral constant expression, but allows real constants to be used and restricts the use of casts to converting one arithmetic type to another. The address constant is a pointer to an object that has static
storage duration or a pointer to a function. You can get these by using the
6.7.2. More initializationThe various types of constants are permitted in various places; integral
constant expressions are particularly important because they are the only
type of expression that may be used to specify the size of arrays and the
values in Here is an example using several initialized variables: #include <stdio.h> #include <stdlib.h> #define NMONTHS 12 int month = 0; short month_days[] = {31,28,31,30,31,30,31,31,30,31,30,31}; char *mnames[] ={ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; main(){ int day_count = month; for(day_count = month; day_count < NMONTHS; day_count++){ printf("%d days in %s\n", month_days[day_count], mnames[day_count]); } exit(EXIT_SUCCESS); }Example 6.14 Initializing ordinary variables is easy: put Initializing arrays is easy for one-dimensional arrays. Just put a list of the values you want, separated by commas, inside curly brackets. The example shows how to do it. If you don't give a size for the array, then the number of initializers will determine the size. If you do give a size, then there must be at most that many initializers in the list. Too many is an error, too few will just initialize the first elements of the array. You could build up a string like this: char str[] = {'h', 'e', 'l', 'l', 'o', 0}; but because it is so often necessary to do that, it is also permitted to use a quoted string literal to initialize an array of chars: char str[] = "hello"; In that case, the null at the end of the string will also be included if there is room, or if no size was specified. Here are examples: /* no room for the null */ char str[5] = "hello"; /* room for the null */ char str[6] = "hello"; The example program used string literals for a different purpose: there they were being used to initialize an array of character pointers; a very different prospect. For structures that have automatic duration, an expression of the right type can be used to initialize them, or else a bracketed list of constant expressions must be used: #include <stdio.h> #include <stdlib.h> struct s{ int a; char b; char *cp; }ex_s = { 1, 'a', "hello" }; main(){ struct s first = ex_s; struct s second = { 2, 'b', "byebye" }; exit(EXIT_SUCCESS); }Example 6.15 Only the first member of a union can be initialized. If a structure or union contains unnamed members, whether unnamed bitfields or padding for alignment, they are ignored in the initialization process; they don't have to be counted when you provide the initializers for the real members of the structure. For objects that contain sub-objects within them, there are two ways of writing the initializer. It can be written out with an initializer for each member: which will assign It is much safer to use internal braces to show what you mean, or one missed value will cause havoc. Always fully bracket initializers—that is much the safest thing to do. It is the same for arrays as for structures: float y[4][3] = { {1, 3, 5}, /* y[0][0], y[0][1], y[0][2] */ {2, 4, 6}, /* y[1][0], y[1][1], y[1][2] */ {3, 5, 7} /* y[2][0], y[2][1], y[2][2] */ };Example 6.18 that gives full initialization to the first three rows of Unless they have an explicit initializer, all objects with static
duration are given implicit initializers—the effect is as if the
constant Initialization of objects with automatic duration is only guaranteed if
their compound statement is entered ‘at the top’. Jumping into the
middle of one may result in the initialization not happening—this is
often undesirable and should be avoided. It is explicitly noted by the
Standard with regard to A declaration inside a function (block scope) can, using various techniques outlined in Chapter 4 [https://publications.gbdirect.co.uk/c_book/chapter4/] and Chapter 8 [https://publications.gbdirect.co.uk/c_book/chapter8/], be made to refer to an object that has either external or internal linkage. If you've managed to do that, and it's not likely to happen by accident, then you can't initialize the object as part of that declaration. Here is one way of trying it: int x; /* external linkage */ main(){ extern int x = 5; /* forbidden */ } Our test compiler didn't notice that one, either. Previous section [https://publications.gbdirect.co.uk/c_book/chapter6/qualifiers_and_derived_types.html] | Chapter contents [https://publications.gbdirect.co.uk/c_book/chapter6/] | Next section [https://publications.gbdirect.co.uk/c_book/chapter6/summary.html] |