C言語 - 配列の知識ポイントを詳しく解説

序文

これは、配列がカバーする基本概念の詳細な説明です。

1. 1次元配列の作成

1.1 1次元配列の作成

定義: 配列は、同じ型の要素のコレクションです。

データの作成方法:

type_t   arr_name   [const_n];
//type_t 是指数组的元素类型
//const_n 是一个常量表达式,用来指定数组的大小`
数据创建的实例:

```c
//代码1
int arr1[5];
//代码2
int count = 3;
int arr2[count];
//代码3
char arr3[29];
float arr4[39];
double arr5[100];

**注意:** C99 標準以前では、配列の作成には [] 内に定数が必要であり、変数は使用できませんでした。 C99 標準では可変長配列の概念がサポートされており、配列のサイズは変数を使用して指定できますが、配列を初期化することはできません。

1.2 1次元配列の初期化

定義: 配列の初期化とは、配列の作成時に配列の内容に適切な初期値を与えることを意味します。

次のようなペン:

int arr1[10] = {
    
    1,2,3};
int arr2[] = {
    
    1,2,3,4};
int arr3[5] = {
    
    12345}char arr4[3] = {
    
    'a',98, 'c'};
char arr5[] = {
    
    'a','b','c'};
char arr6[] = "abcdef";

配列の作成時に特定のサイズを指定したくない場合は、配列を初期化する必要があります。配列の要素数は初期化内容に基づいて決定されます。
次に、次の 2 つのコード セットのメモリ割り当てを見てみましょう。

char arr1[] = "abc";//代码1
char arr2[3] = {
    
    'a','b','c'};代码2

このうち、コード 1「abc」は \0 を省略しているため、コード 1 の実際のサイズは 4 です
。コード 2 は省略されていないため、そのサイズは 3 です。
結論:

1. 「 " 」を使用して配列を表す場合、配列の末尾のスペースが省略されるため、配列の実際のサイズは 1 増やす必要があります
2. { } を使用して配列を表現する場合、 配列内の要素の数が実際の配列のサイズになります

1.3 1次元配列の使用

前の記事では、添字参照演算子 [ ] について紹介しました。実際、これは配列にアクセスするための演算子です。
例:

#include <stdio.h>
int main()
{
    
    
 int arr[10] = {
    
    0};//数组的不完全初始化
    //计算数组的元素个数
    int sz = sizeof(arr)/sizeof(arr[0]);
 //对数组内容赋值,数组是使用下标来访问的,下标从0开始。所以:
 int i = 0;//做下标
 for(i=0; i<10; i++)//这里写10,好不好?
 {
    
    
 arr[i] = i;
 } 
 //输出数组的内容
 for(i=0; i<10; ++i)
 {
    
    
 printf("%d ", arr[i]);
 }
 return 0;
}

要約:

  1. 配列には、0 から始まる添え字を使用してアクセスします。
  2. 配列のサイズは計算できます。

1.4 1次元配列のメモリへの格納

次に、メモリ内の配列の保存について学習します。
次のコードを見てみましょう。

#include <stdio.h>
int main()
{
    
    
 int arr[10] = {
    
    0};
 int i = 0;
    int sz = sizeof(arr)/sizeof(arr[0]);
    
 for(i=0; i<sz; ++i)
 {
    
    
 printf("&arr[%d] = %p\n", i, &arr[i]);
 }
 return 0;
}

コード出力は次のとおりです。
ここに画像の説明を挿入します
観察すると、配列の添え字が増加するにつれて、要素のアドレスも徐々に増加することがわかります。
このことから、次のように結論付けることができます。

配列はメモリ内に連続して格納されます。

2. 2次元配列の作成と初期化

2.1 2次元配列の作成

配列の作成

int arr[3][4];
char arr[3][5];
double arr[2][4];

2.2 2次元配列の初期化

配列の初期化

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

: 2 次元配列が初期化されている場合、行は省略できますが、列は省略できません

2.3 2次元配列の使用

実際、2 次元配列の使用は 1 次元配列の使用と似ており、添え字によっても実装されます。
例:

#include <stdio.h>
int main()
{
    
    
 int arr[3][4] = {
    
    0};
 int i = 0;
 for(i=0; i<3; i++)
 {
    
    
 int j = 0;
 for(j=0; j<4; j++)
 {
    
    
 arr[i][j] = i*4+j;
 }
 }
 for(i=0; i<3; i++)
 {
    
    
 int j = 0;
 for(j=0; j<4; j++)
 {
    
    
 printf("%d ", arr[i][j]);
 }
 }
 return 0;
}

2.4 メモリへの 2 次元配列の保存

1 次元配列と同様に、2 次元配列の要素も出力しようとします。

#include <stdio.h>
int main()
{
    
    
 int arr[3][4];
 int i = 0;
 for(i=0; i<3; i++)
 {
    
    
 int j = 0;
 for(j=0; j<4; j++)
 {
    
    
 printf("&arr[%d][%d] = %p\n", i, j,&arr[i][j]);
 }
 }
 return 0;
}

出力:
ここに画像の説明を挿入します
出力結果から、実際には 2 次元配列のメモリが 1 次元配列と同様に連続的に格納されていることが分析できます。

3. 範囲外の配列

配列の添字は範囲に制限があります。

配列の添字は 0 から始まります。配列に n 個の要素がある場合、最後の要素の添字は n-1 になります。
したがって、配列の添字が 0 より小さいか、n-1 より大きい場合、配列は配列の有効な空間のアクセスを超えて範囲外にアクセスされます。
C 言語自体は配列添字の範囲外チェックを実行しないため、コンパイラが必ずしもエラーを報告するとは限りません。ただし、コンパイラがエラーを報告しない場合、コンパイラはエラーを報告しません。は、プログラムが正しいことを意味します。
プログラマが独自のコードを作成するときは、範囲外チェックを自分で行うのが最善です

#include <stdio.h>
int main()
{
    
    
 int arr[10] = {
    
    1,2,3,4,5,6,7,8,9,10};
    int i = 0;
    for(i=0; i<=10; i++)
   {
    
    
        printf("%d\n", arr[i]);//当i等于10的时候,越界访问了
   }
 return 0;
}

2 次元配列の行と列も範囲外になる可能性があります。

4. 関数パラメータとしての配列

コードを記述するときは、次のように配列をパラメーターとして関数に渡します。バブル ソート (アルゴリズムの考え方が含まれる) 関数を実装したいと考えています。

4.1 バブルソート機能の設計が間違っている

整数配列をソートするには、次のような関数を使用します。

//方法1:
#include <stdio.h>
void bubble_sort(int arr[])
{
    
    
 int sz = sizeof(arr)/sizeof(arr[0]);//认真考虑这样对吗?
    int i = 0;
 for(i=0; i<sz-1; i++)
   {
    
    
        int j = 0;
        for(j=0; j<sz-i-1; j++)
       {
    
    
            if(arr[j] > arr[j+1])
           {
    
    
                int tmp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = tmp;
           }
       }
   }
}
int main()
{
    
    
    int arr[] = {
    
    3,1,7,5,8,9,0,2,4,6};
    bubble_sort(arr);//能可以正常排序?
    for(i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
   {
    
    
        printf("%d ", arr[i]);
   }
    return 0;
}

方法 1、問題があるので問題を見つけてみましょう。デバッグ後、bubble_sort 関数内の sz が 1 であることがわかります。
配列が関数のパラメータとして使用される場合、配列全体が渡されませんか?
この時点で、別の知識ポイントに到達します。次に何が起こったのか知りたい場合は、 次のセクションのお知らせをお読みください。

4.2 アレイ名とは何ですか?

次のコードを見てみましょう。

#include <stdio.h>
int main()
{
    
    
    int arr[10] = {
    
    1,23,4,5};
 printf("%p\n", arr);
    printf("%p\n", &arr[0]);
    printf("%d\n", *arr);
    //输出结果
    return 0;
}

配列名は、配列の最初の要素のアドレスです。

この文はずっと前に聞いたことがあるはずですが、例外となるケースが 2 つあります。
配列名が最初の要素のアドレスの場合:

int arr[10] = {
    
    0};
printf("%d\n", sizeof(arr));

の出力結果は次のようになります。 40?
追加の結論:

  1. sizeof (配列名) は、配列全体のサイズを計算します。sizeof 内には別の配列名があります。配列名は配列全体を表します
  2. &配列名、取り出されるのは配列のアドレスです。 &配列名。配列名は配列全体を表します。

これら 2 つの場合を除き、すべての配列名は配列の最初の要素のアドレスを表します。

4.3 バブルソート機能の正しい設計

配列パラメータが渡されるとき、実際には配列の最初の要素のアドレスのみが渡されます。
したがって、関数のパラメータ部分が配列の形式で記述されている場合でも、 int arr[] は依然としてポインタ int *arr を表します。
すると、関数内の sizeof(arr) の結果は 4 になります。
次に、正しいコードを見てみましょう。

//方法2
void bubble_sort(int arr[], int sz)//参数接收数组元素个数
{
    
    
 //代码同上面函数
}
int main()
{
    
    
    int arr[] = {
    
    3,1,7,5,8,9,0,2,4,6};
    int sz = sizeof(arr)/sizeof(arr[0]);
    bubble_sort(arr, sz);//是否可以正常排序?
    for(i=0; i<sz; i++)
   {
    
    
        printf("%d ", arr[i]);
   }
    return 0;
}

これで共有は終わりです
不備や間違いがある場合は、コメント欄で修正してください。

おすすめ

転載: blog.csdn.net/weixin_73807021/article/details/129106294