Understanding Arrays in C Language

This article explains arrays in the C language,and the fundamentals are always worth spending 85% of your time learning well, recommended for collection!

Overview
1. Definition
2. Initialization
3. Common Mistakes
4. Test Code for this Section

1. Definition

An array is a block of data that exists continuously in memory, used to storedata of the same type.

Note that it must be of the same type, which can be int, pointers, structures, or even arrays (an array itself is a composite data type).

Beginners often confuse arrays with other types; the only trick is toremember the definition— an array is a data type that stores data of the same type, so just look at what it stores!

For example

Code Array Type
int arr[5] One-dimensional array arr that stores 5 int elements
int* arr[5] One-dimensional array arr that stores 5 int* elements, which means it stores 5 int pointers
int** arr[5] One-dimensional array arr that stores 5 int** elements, which means it stores 5 int* pointers; int** is a pointer to a pointer, meaning it is itself a pointer that stores pointers (of int type)
int* arr[2][5] This is a two-dimensional array, with the first dimension being 2 and the second dimension being 5, where each element of the first dimension is a one-dimensional array storing 5 int pointers, and each element of the second dimension is an int pointer
struct person_* person[5] This is a one-dimensional array of structure pointers, containing 5 elements of struct person_ type

2. Initialization

            Divided into **two categories**, as follows
Type Characteristics Essence Classification
Static Initialization Appears as [] Allocated at compile time with everything set up 1. Complete2. Partial3. C String4. VLA
Dynamic Initialization Essentiallypointer operations Works at runtime only 1. malloc2. calloc3. realloc4. free

① Four Types of Static Initialization

Static means that all information about the array, such assize, andmemory location, is completely determined during the compilation period. The common static initializations are as follows: four types:

In fact, any occurrence ofsquare brackets[] indicates static initialization, as the size and location of the internal data block are determined at compile time! For example, int arr[5], int arr[]={….}, int arr[len]

Static Initialization Type Code Description
Complete Initialization int arr[5]={1,2,3,4,5} All memory areas are filled
Partial Initialization int arr[5]={1,2,3} The last two memory cells default to 0
C String char arr[6]=”hello” The size of a C-style string is one more than the literal because the compiler automatically adds anull terminator \0 at the end of the string
VLA (Variable Length Array) int arr[len] Supported since C99, this writing is not recommended; it essentially confirms the length len atruntime and allocates memory on thestack.

2. Code

Test code can be found at the end of this article.

3. Controversy over VLA

VLA is quite special; if we classify it based onstack vs. dynamic, VLA belongs to static initialization. However, if we classify it based onmemory allocation at compile time vs. runtime, VLA belongs to dynamic initialization. We classified it based on the stack method above. However, we must remember,do not use VLA in actual development; in fact, this is a mistake in C language. You can uniformly use the following dynamic initialization as a replacement!

② Three Types of Dynamic Initialization

This sectionis essentially pointer operations; if you have no foundation, please read the following article:

We know that the size of an array needs to be known at compile time, butwe often only know its size at runtime. Although the VLA mechanism proposed in C99 seems to solve this problem, it still has many limitations. Is there a better alternative? Yes—using pointers for dynamic initialization!

1. Definition

Definition: Dynamic initialization refers to the mechanism ofdynamically allocating memory for an array in the heap during program execution, which requires manual memory release.

Any data structure can be dynamically initialized!

2. Classification

There are four functions

Dynamic Initialization Function Explanation Notes
malloc Allocates a block of memory in the heap and returns a pointer to that memory The allocated memory isuninitialized
calloc Allocates a block of memory in the heap and returns a pointer to that memory The allocated memory isinitialized to NULL
realloc Takes a pointer returned bymalloc orcalloc, reallocates a block of memory at that pointer (in the heap) (can be larger or smaller), and returns a pointer to that memory The original part of the allocated memory isretained, and the new part isuninitialized
free Releases the memory resource pointed to by the pointer returned by the above three functions Can only release these three types; releasing others willcause segmentation faults andprogram crashes

3. Signatures

void* malloc(size_t size);
void* calloc(size_t nmemb, size_t size);
void* realloc(void* ptr, size_t new_size);
void free(void* ptr);

4. Special Notes

Note the difference between malloc and calloc functions:

  • calloc initializes the memory data to0, while malloc isuninitialized.
  • calloc is slower, malloc is faster.

5. Code

Test code can be found at the end of this article.

3. Common Mistakes

1. Calculating Length

int length=sizeof(arr)/sizeof(arr[0]);// Method to calculate length specific to arrays

Note,it must be an array to calculate length this way (in other words, onlythe last element can have []); if it is a pointer, it cannot be (and in fact, this is a common mistake I make!). For example:

char *b = "hello";
int len_b = sizeof(b) / sizeof(b[0]);

Because b<span>is essentially a pointer, not an array</span>, the size of the pointer is 8 bytes, and the character is 1 byte, so the printed result is 8, but in reality, it is only 5 (plus the \0 makes 6):

Complete code and results:

#include <stdio.h>
int main(void)
{
    char a[] = "hello";
    int len_a = sizeof(a) / sizeof(a[0]);
    printf("len = %d\n", len_a);
    char *b = "hello";
    int len_b = sizeof(b) / sizeof(b[0]);
    printf("len = %d\n", len_b);
    return 0;
}

Results:

len = 6
len = 8

2. Arrays Cannot Be Assigned

Note that arrays are the only composite data type that cannot use<span>=</span> for assignment!

Here are two classic errors:

1. Direct Array Assignment Error

Understanding Arrays in C Language

2. String Array Assignment

This is probably the most common error with arrays! Just remember one thing: arrays cannot be<span>=</span> assigned! So what to do? Use pointers instead.

Code is as follows:

#include <stdio.h>

int main(void)
{
    /**
     * data descp: Essentially an array, a memory area determined by the compiler, which is an immutable left value
     */
    char char1[6] = "hello";
    char1 = "Ethan";// Error! Arrays cannot be assigned!
    /**
     * data descp: Essentially a pointer, a mutable left value, pointing to the memory area of the code segment .rodata
     */
    char *char2 = "world";
    char2 = "Ethan";
    return 0;
}

Error results:Understanding Arrays in C Language

Reason Why Arrays Cannot Use = for Assignment

Why can’t arrays use<span>=</span> for assignment? We must think about the logic behind<span>=</span>. Normally, we use ptr1=ptr2 to complete pointer assignment, which means ptr1 points to the memory area pointed to by ptr2, which is reasonable. However, the uniqueness of arrays is that they are a direct abstraction ofcontinuous data blocks of the same data type in memory,not a conventional data type (like int, struct, etc.). The “address” of the memory block represented by the array is aconstant determined at compile time (existing at<span>stack / global area</span> and otherfixed locations), which cannot be modified. Can this memory block equal that memory block?? Obviously, it does not make sense!This is the fundamental reason why arrays cannot use<span>=</span> for assignment—memory immutability! Knowing the reason is just as important as knowing the facts! Simple is difficult!

3. Array Assignment Methods

Since we cannot use<span>=</span>, how can we assign arrays? The answer is to useelement-wise traversal or memory operation functions! There are several methods:

Array Assignment Method Code
Element-wise traversal, operating on elements for(…){arr[i]=brr[i]}
memcpy function (all-purpose) void * memcpy(void * dst, const void * src, size_t n)
sprintf function (for char usage) int sprintf (char * stream, const char * format, …)

Array Assignment Code

Test code can be found at the end of this article.

Complete Code for this Section

1. Testing Static Initialization of Arrays

#include <stdio.h>
#include <string.h>
/**
 * data descp: Define enumeration for different data types
 */
typedef enum
{
    TYPE_INT,
    TYPE_CHAR
} DataType;
/**
 * func descp: General print function for data types
 */
void print_array(void *arr, int len, DataType type)
{
    if (arr == NULL || len <= 0)
        return;

    size_t elem_size = (type == TYPE_INT) ? sizeof(int) : sizeof(char);

    for (int i = 0; i < len; i++)
    {
        void *elem_ptr = (char *)arr + i * elem_size; // Offset by element size

        if (type == TYPE_INT)
        {
            int value;
            memcpy(&amp;value, elem_ptr, elem_size); // Safely copy data
            printf("%d\t", value);
        }
        else
        {
            char value;
            memcpy(&amp;value, elem_ptr, elem_size);
            printf("%c\t", value);
        }
    }
    printf("\n");
}

int main()
{
    int arr1[5] = {1, 2, 3, 4, 5};
    int arr2[5] = {1, 2, 3};
    char arr3[6] = "hello";
    int len;
    printf("enter VLA's length:\n");
    scanf("%d", &amp;len);
    int arr4[len];
    printf("enter VLA's element:\n");
    for (int i = 0; i < len; i++)
    {
        scanf("%d", &amp;arr4[i]);
    }
    /**
     * data descp: Print all
     */
    printf("print all:\n");
    {
        print_array(arr1, 5, TYPE_INT);
        print_array(arr2, 5, TYPE_INT);
        print_array(arr3, 5, TYPE_CHAR);
        print_array(arr4, 5, TYPE_INT);
    }
}

Results:

enter VLA's length:
5
enter VLA's element:
1 3 4 5 7
print all:
1	2	3	4	5
1	2	3	0	0
h	e	l	l	o
1	3	4	5	7

2. Testing Dynamic Initialization of Arrays

#include <stdio.h>
#include <stdlib.h>
void assign_and_print(int *p, int n)
{
    for (int i = 0; i < n; i++)
    {
        p[i] = i + 1;
    }
    for (int i = 0; i < n; i++)
    {
        printf("%d ", p[i]);
    }
    printf("\n\n");
}

void only_print(int *p, int n)
{
    for (int i = 0; i < n; i++)
    {
        printf("%d ", p[i]);
    }
    printf("\n\n");
}

int main(void)
{
    printf("use malloc:\n");
    int *p1 = (int *)malloc(10 * sizeof(int));
    assign_and_print(p1, 10);
    printf("use calloc:\n");
    int *p2 = (int *)calloc(10, sizeof(int));
    assign_and_print(p2, 10);
    printf("use realloc:\n");
    int *p3 = (int *)realloc(p1, 20 * sizeof(int)); /* Note that this is byte size! Must fill 20 * sizeof(int), cannot fill 20 */
    only_print(p3, 20);
    assign_and_print(p3, 20);
    // free(p1); Note that p1 cannot be freed here because it has been taken over by p3 returned from realloc!
    free(p2);
    free(p3);
    return 0;
}

Results:

Understanding Arrays in C Language
use malloc:
1 2 3 4 5 6 7 8 9 10

use calloc:
1 2 3 4 5 6 7 8 9 10

use realloc:
1 2 3 4 5 6 7 8 9 10 1885106287 1919252335 1835628077 1635017564 943027047 1547322683 1987011950 1650224489 1161522793 1701731386

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Here, especially note that the part exceeding realloc is random (<span>1885106287 1919252335 are all undefined</span>), but the original part from 1 to 10 remains unchanged!

3. Testing Array Assignment Methods

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void only_print(int *p, int n)
{
    for (int i = 0; i < n; i++)
    {
        printf("%d ", p[i]);
    }
    printf("\n\n");
}
void only_print_char(char *p, int n)
{
    for (int i = 0; i < n; i++)
    {
        printf("%c ", p[i]);
    }
    printf("\n\n");
}
int main(void)
{
    int arr1[5] = {1, 2, 3, 4, 5};
    int arr2[5] = {6, 7, 8, 9, 10};
    printf("before assign:\n");
    only_print(arr1, 5);
    only_print(arr2, 5);
    // arr1=arr2; Syntax error
    /**
     * data descp: Array assignment method 1—traversal
     */
    for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
    {
        arr1[i] = arr2[i];
    }
    printf("before assign:\n");
    only_print(arr1, 5);
    only_print(arr2, 5);

    /**
     * data descp: Array assignment method 2—memcpy
     */
    for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
    {
        memcpy(&amp;arr1[i], &amp;arr2[i], sizeof(arr1[i])); // Note that this is the byte size of a single element! Must fill sizeof(arr1[i]), cannot fill sizeof(arr1)
    }
    /**
     * data descp: Array assignment method 3—sprintf (for char)
     */
    char arr3[5] = {'1', '2', '3', '4', '5'};
    char arr4[5] = {'6', '7', '8', '9', '0'};
    printf("before assign:\n");

    only_print_char(arr3, 5);
    only_print_char(arr4, 5);
    for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
    {
        sprintf(arr3 + i, "%c", arr4[i]); // Note that this can only be char type!
    }
    printf("after assign:\n");

    only_print_char(arr3, 5);
    only_print_char(arr4, 5);
    return 0;
}

Results

before assign:
1 2 3 4 5

6 7 8 9 10

before assign:
6 7 8 9 10

6 7 8 9 10

before assign:
1 2 3 4 5

6 7 8 9 0

after assign:
6 7 8 9 0

6 7 8 9 0

Conclusion

Well, this is the knowledge about arrays in this section. We have discussed:

1. Definition
2. Initialization
3. Common Mistakes
Static Initialization (4 types) Characteristics of Length Calculation
Dynamic Initialization (4 types) Note on Assignment Methods

If you cannot explain each item in this table, then review the content above again! See you next time!

About Xiaokang

😉 Hehe, I am Xiaokang, a programmer who loves<span>C language</span>, <span>Linux</span>, and <span>low-level development</span>. Below is my WeChat, looking forward to learning and communicating with you!

Understanding Arrays in C Language

(Please note when adding WeChat)~

Leave a Comment