The first chapter lays the foundation of programming. This article is about 1.6.1 arrays and pointers.
> > > 1.6.1 Array and Pointer
Array
(1) Array Declaration
We know that a variable of a basic data type can only hold one piece of data, such as:
Int data = 0x64;
But what if you need to store a set of int data, like 1, 2, and 3? At least three variables—data0, data1, and data2—are required, such as:
Int data0 = 1, data1 = 2, data2 = 3;
Since data comes in various forms—character types, numerical types, and others—it's clear that basic data types alone aren't enough. Is it possible to construct new data types by combining and abstracting primitive data types? Yes, arrays serve exactly this purpose.
Conceptually, the integers 1, 2, and 3 are all of the same data type. The commonality among the three variables—data0, data1, and data2—is data, while the difference lies in their respective subscripts. Therefore, we can abstract data0, data1, and data2 into a single name and use subscripts to distinguish between them—data[0], data[1], and data[2]. For instance:
Int data[3]; // This is interpreted as data being an int array with 3 elements.
This transforms data[3] into an array of data[0], data[1], and data[2] that store three int-type data points: 1, 2, and 3. These can then be assigned individually:
Data[0] = 1, data[1] = 2, data[2] = 3;
Alternatively, you can declare and initialize an array like this:
Int data[3] = {1, 2, 3};
The array is typically referred to as the array (variable) name, while data[0], data[1], and data[2] are considered individual variables. Thus, an array organizes several variables of the same data type in an orderly manner, assigns them a collective name, and distinguishes them via subscripts.
Since arrays are built on top of other types, C treats arrays as constructed types, requiring the declaration of the element type when defining an array. For example, an array of type int, an array of type float, or an array of other types. Arrays can even contain other array types, creating what's known as a multidimensional array.
(2) Subscripts and Variable Values
Here, we define an array type variable named data, composed of variables data[0], data[1], and data[2] storing three int-type data points: 1, 2, and 3. Each variable within an array is typically referred to as an array element, and array elements are sequentially numbered. These numbers are also known as the subscripts of the array elements.
Due to the subscripts, the position of an array element in memory is uniquely determined. Subscripts always start at 0. The last element's subscript is the total number of elements minus 1 (i.e., 2). Data[0] is called the first element, data[1] the second element, and data[2] the third element, meaning all elements are stored contiguously in memory.
Visually, an array is a collection of pairs of subscripts (or indexes) and values:
The function Create(data, size) creates a new empty array of the appropriate size. Initially, each item in the array is undefined. The Retrieve operation accepts an array of data and a subscript index. If the index is valid, the operation returns the value associated with the index; otherwise, an error is generated. The Store operation accepts an array of data, a subscript index, and an item value, returning a new array with the updated value.
Clearly, any constant expression of the int system can be used as an array element's subscript. For example:
Int array[3+5]; // Legitimate
Int array['a']; // Int array[97];
The above definitions are valid because the constant expression representing the number of elements has a definite meaning at compile time, and a fixed-size space is explicitly allocated as defined by the variable.
Using symbolic constants increases the flexibility of the array. However, if the definition takes the following form:
Int n = 5;
Int array[n]; // Illegal
This is because standard C considers the number n of array elements not to be a constant. Although the compiler might seem to "see" the value of n, int array[n] cannot determine the size of its space at compile time. The correct way to define an array using symbolic constants is:
#define N 10
Int array[N];
You can modify the value of the constant N according to your needs.
Since the valid range of an array element's subscript is 0 to N-1, data[N] does not exist. However, C does not check whether the subscript is out of bounds. Accessing an element beyond the array's end results in accessing memory unrelated to the array, causing potential issues. Why does C allow this? It's due to C's trust in the programmer—skipping boundary checks makes the program run faster, so the compiler doesn't need to check every subscript error. Checking each subscript value at runtime for security reasons would slow down the program. C assumes that programmers can write correct code, resulting in faster execution. However, not all programmers can ensure this. Crossing boundaries is the most common beginner mistake, so always pay attention to keeping the subscript within a reasonable range.
(3) Address and Type of the Variable
When variables data[0], data[1], and data[2] are used as operands for &, &data[0] is a pointer to the variable data[0], &data[1] is a pointer to data[1], and &data[2] is a pointer to data[2]. The variables data[0], data[1], and data[2] are of type int, whereas &data[0], &data[1], and &data[2] are of type int *const, which is a pointer to a constant, abbreviated as a constant pointer whose value cannot be modified. For example:
Int a;
Int * const ptr = &a;
Ptr = NULL; // Attempt to modify, compilation error
&a = NULL; // Attempt to modify, compilation error
Similarly, &data is a pointer to the variable data. What type is data?
According to the variable declaration specification, after removing the identifier data, the remaining "int [3]" is the type of data, which is usually interpreted as an array type consisting of three ints, referred to as an array type. The purpose is to inform the compiler how much memory to allocate—a data type of three integer elements. The data type testing procedure is detailed in Listing 1.20.
Listing 1.20 Data Type Test Program
1 #include
2
3 void f(int x);
4 int main(int argc, char *argv[])
5 {
6 int data[3];
7 f(data);
8 return 0;
9}
The warning prompt from the compiler—"function: 'int' differs in levels of indirection from 'int [3]'—indicates that the array variable data type is not int but int [3], an array type. While this simplifies compiler development, it can confuse beginners due to the ambiguity of the concept. In fact, the array should be defined like this:
Int [3] data;
That is, int is combined with [3]. What type is &data?
When data is used as an operand of &, &data is a pointer to data. Since the type of data is int [3], &data is a pointer to the "int [3] array type" variable data, referred to as an array pointer. Its type is int (*)[3], which is the pointer type to int [3]. Why use "()" to enclose "*"? If you don't enclose the asterisk in parentheses, then "int (*)[3]" becomes "int *[3]", and the int *[3] type is an array of pointers to int (with 3 elements), which is the grammar rule agreed upon when designing the compiler.
Is the type of &data "int (*)[3]"? An example of its verification procedure is shown in Listing 1.21.
Listing 1.21 &data Type Tester
1 #include
2 int main(int argc, char *argv[])
3 {
4 int data[3];
5 int b = &data;
6 return 0;
7}
The warning prompt from the compiler—"‘int’ differs in levels of indirection from ‘int (*)[3]’"—indicates that the type of &data is int (*)[3].
(4) sizeof(data)
When data is used as the operand of sizeof, it returns the length of the entire array. Here, sizeof(data) has a size of 12, meaning the total size of the three elements is 4×3=12, and the system considers the "1" in &data+1 to be offset by the size of the array, making &data +1 the address of the next unknown storage space (i.e., out of bounds). In little-endian mode, the way the array is stored in memory is shown in Figure 1.10.
Figure 1.10 Â Array Storage
How do you find the corresponding array element? A common method is to calculate the address of an array element by "base address + offset of array". Here, the address of the first element &data[0] is called the base address, and the offset is the subscript value multiplied by the size of each element sizeof(int). Assuming the address of the array element &data[0] is A and the actual address in memory is 0x22FF74, then the value of &data[1] is:
A + 1×sizeof(int) = (unsigned int)data + 4 = 0x22FF74 + 4 = 0x22FF78
The value of &data[2] is:
A + 2×sizeof(int) = (unsigned int)data + 8 = 0x22FF74 + 8 = 0x22FF7C
In fact, when writing data[i] in C, C translates it into a pointer to an int. Data is a pointer to data[0], and data+i points to data[i]. Therefore, regardless of the type of the data array, there is always data+i equal to data[i], so *(data+i) equals data[i]. The corresponding test sample program is detailed in Listing 1.22.
Program List  1.22  Variable Address Test Procedure
1 #include
2 int main(int argc, char *argv[])
3 {
4 int data[3] Â = {1, 2, 3};
5 printf("%x, %x, %x, %x, %x", &data[0], &data[1], &data[2], &data, &data+1);
6 return 0;
7 }
Practice has shown that although &data[0] is not the same type as &data, their values are equal. It can also be seen that the elements of the array are stored contiguously. If you divide the size of the array variable's memory by the size of the space occupied by an element in the array variable, you can get the number of array elements, which is:
Int numData = sizeof(data) / sizeof(data[0]);
Of course, you can also use a macro definition to calculate the number of array elements:
#define NELEMS(data) (sizeof(data) / sizeof(data[0])
When an array is used as a parameter to a function, all parameters of the C language function must be declared inside the function. However, since no new storage space is allocated to the array inside the function, the capacity of the one-dimensional array is only defined in the main program. Clearly, if a function needs to get the size of a one-dimensional array, it must be passed to the function as an argument or accessed as a global variable.
In the field of sensor technology, SVLEC has a complete set of diverse technologies and their different working principles. You can order high-quality Sensors and systems that are suitable for various purposes and meet various requirements from our company, from linear displacement detection and identification to target detection and fluid measurement. Suitable for daily industrial applications and arduous use in critical environments. To match it, we provide you with the best network and connection technology and a wide range of accessory products.
Sensor Actuator, Pressure Switch,Led light,Multi-Functional Signal Light, led indicator
Kunshan SVL Electric Co.,Ltd , https://www.svlelectric.com