[C言語] 文字列の2次元配列の使い方を解説

C言語における文字列の2次元配列は、複数の文字列を格納するための便利なデータ構造です。

2次元配列は、行と列で構成され、各行に文字列を格納することができます。

例えば、char names[3][10]のように宣言すると、3つの文字列を格納でき、それぞれの文字列は最大9文字(終端の\\0を含めて10文字)まで格納可能です。

文字列の2次元配列を使用することで、簡単に複数の文字列を管理し、操作することができます。

この記事でわかること
  • 文字列の2次元配列の基本的な宣言と初期化方法
  • 文字列の2次元配列を操作する方法と注意点
  • メモリ管理の重要性と動的メモリ確保の利点と欠点
  • 文字列のソート、検索、フィルタリングの応用例

目次から探す

文字列の2次元配列とは

C言語における文字列の2次元配列は、文字列を格納するための配列の一種です。

通常、文字列は文字の配列として扱われますが、2次元配列を使用することで、複数の文字列を一つの変数で管理することが可能になります。

これは、例えば、複数の名前や単語を一度に扱いたい場合に非常に便利です。

2次元配列は、行と列で構成されており、行が文字列の数、列が各文字列の最大長を表します。

これにより、各行に異なる文字列を格納することができます。

以下に、文字列の2次元配列の基本的な構造を示します。

#include <stdio.h>
int main() {
    // 3つの文字列を格納する2次元配列
    char names[3][10] = {
        "Taro",   // 1行目
        "Hanako", // 2行目
        "Jiro"    // 3行目
    };
    // 配列の内容を出力
    for (int i = 0; i < 3; i++) {
        printf("%s\n", names[i]);
    }
    return 0;
}

この例では、namesという2次元配列を宣言し、3つの文字列を格納しています。

それぞれの文字列は最大で9文字(終端文字を含めて10文字)まで格納可能です。

プログラムを実行すると、配列に格納された各文字列が順に出力されます。

文字列の2次元配列の宣言と初期化

宣言方法

文字列の2次元配列を宣言する際には、まず配列の行数と列数を指定します。

行数は格納したい文字列の数、列数は各文字列の最大長を表します。

以下に基本的な宣言方法を示します。

// 5つの文字列を格納する2次元配列を宣言
char words[5][20];

この例では、wordsという名前の2次元配列を宣言し、5つの文字列を格納できるようにしています。

各文字列は最大で19文字(終端文字を含めて20文字)まで格納可能です。

初期化の方法

2次元配列を宣言すると同時に初期化することも可能です。

初期化の際には、各行に格納する文字列を波括弧 {} で囲んで指定します。

// 3つの文字列を初期化
char fruits[3][10] = {
    "Apple",   // 1行目
    "Banana",  // 2行目
    "Cherry"   // 3行目
};

この例では、fruitsという2次元配列を宣言し、3つの文字列を初期化しています。

各文字列は最大で9文字(終端文字を含めて10文字)まで格納可能です。

サイズ指定の注意点

2次元配列を使用する際には、サイズ指定に注意が必要です。

特に、各文字列の最大長を適切に設定しないと、バッファオーバーフローが発生する可能性があります。

以下の点に注意してください。

  • 各文字列の最大長には、終端文字 \0 のためのスペースを含める必要があります。
  • 配列のサイズを超える文字列を格納しようとすると、予期しない動作やプログラムのクラッシュを引き起こす可能性があります。

例えば、以下のように宣言すると、各文字列は最大で4文字までしか格納できません。

// 各文字列は最大で4文字(終端文字を含めて5文字)
char colors[3][5] = {
    "Red",    // 1行目
    "Blue",   // 2行目
    "Green"   // 3行目(この場合、"Gree"までしか格納できない)
};

この例では、colors配列の3行目に格納される文字列は、”Green”のうち最初の4文字までしか格納されません。

終端文字を含めたサイズ指定が重要であることがわかります。

文字列の2次元配列の操作

要素へのアクセス方法

文字列の2次元配列の要素にアクセスするには、配列のインデックスを使用します。

行番号と列番号を指定することで、特定の文字にアクセスできます。

ただし、文字列全体にアクセスする場合は、行番号のみを指定します。

#include <stdio.h>
int main() {
    char animals[3][10] = {
        "Cat",
        "Dog",
        "Bird"
    };
    // 2行目の文字列を出力
    printf("2行目の動物: %s\n", animals[1]);
    // 1行目の3文字目を出力
    printf("1行目の3文字目: %c\n", animals[0][2]);
    return 0;
}

この例では、animals配列の2行目の文字列全体と、1行目の3文字目にアクセスしています。

要素の変更

2次元配列の要素を変更するには、特定のインデックスを指定して新しい値を代入します。

文字列全体を変更する場合は、strcpy関数を使用することが一般的です。

#include <stdio.h>
#include <string.h> // strcpyを使用するために必要
int main() {
    char colors[3][10] = {
        "Red",
        "Blue",
        "Green"
    };
    // 2行目の文字列を変更
    strcpy(colors[1], "Yellow");
    // 変更後の配列を出力
    for (int i = 0; i < 3; i++) {
        printf("%s\n", colors[i]);
    }
    return 0;
}

この例では、colors配列の2行目の文字列を”Blue”から”Yellow”に変更しています。

文字列のコピーと結合

文字列の2次元配列において、文字列をコピーしたり結合したりするには、strcpystrcatといった標準ライブラリ関数を使用します。

#include <stdio.h>
#include <string.h>
int main() {
    char greetings[2][20] = {
        "Hello",
        "World"
    };
    char message[40];
    // 1行目の文字列をコピー
    strcpy(message, greetings[0]);
    // スペースを追加
    strcat(message, " ");
    // 2行目の文字列を結合
    strcat(message, greetings[1]);
    // 結果を出力
    printf("結合されたメッセージ: %s\n", message);
    return 0;
}

この例では、greetings配列の2つの文字列をmessageにコピーし、結合しています。

strcpyで最初の文字列をコピーし、strcatでスペースと2番目の文字列を結合しています。

結果として、”Hello World”というメッセージが出力されます。

文字列の2次元配列を使ったプログラム例

名前リストの管理

文字列の2次元配列は、名前リストの管理に非常に便利です。

以下の例では、複数の名前を格納し、リストとして出力します。

#include <stdio.h>
int main() {
    char names[5][20] = {
        "Yamada",
        "Suzuki",
        "Tanaka",
        "Kobayashi",
        "Sato"
    };
    printf("名前リスト:\n");
    for (int i = 0; i < 5; i++) {
        printf("%s\n", names[i]);
    }
    return 0;
}

このプログラムは、5つの名前を格納した2次元配列を使用して、名前リストを出力します。

各名前は最大19文字まで格納可能です。

単語の分類

文字列の2次元配列を使って、単語をカテゴリごとに分類することができます。

以下の例では、動物と果物のリストを作成します。

#include <stdio.h>
int main() {
    char animals[3][10] = {
        "Cat",
        "Dog",
        "Bird"
    };
    char fruits[3][10] = {
        "Apple",
        "Banana",
        "Cherry"
    };
    printf("動物のリスト:\n");
    for (int i = 0; i < 3; i++) {
        printf("%s\n", animals[i]);
    }
    printf("\n果物のリスト:\n");
    for (int i = 0; i < 3; i++) {
        printf("%s\n", fruits[i]);
    }
    return 0;
}

このプログラムは、動物と果物の2つのカテゴリに単語を分類し、それぞれのリストを出力します。

テキストデータの解析

文字列の2次元配列を使用して、テキストデータを解析することも可能です。

以下の例では、文章を単語に分割し、各単語を配列に格納します。

#include <stdio.h>
#include <string.h>
int main() {
    char text[] = "C programming is fun";
    char words[10][20];
    int i = 0;
    // 文字列を空白で分割
    char *token = strtok(text, " ");
    while (token != NULL) {
        strcpy(words[i], token);
        i++;
        token = strtok(NULL, " ");
    }
    printf("分割された単語:\n");
    for (int j = 0; j < i; j++) {
        printf("%s\n", words[j]);
    }
    return 0;
}

このプログラムは、strtok関数を使用して文章を単語に分割し、各単語を2次元配列に格納します。

結果として、”C”, “programming”, “is”, “fun”の4つの単語が出力されます。

文字列の2次元配列のメモリ管理

メモリの確保と解放

C言語では、文字列の2次元配列を動的に管理するために、mallocfreeといったメモリ管理関数を使用します。

動的メモリ確保を行うことで、実行時に必要なメモリを柔軟に確保できます。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
    int numStrings = 3;
    int maxLength = 20;
    // 文字列の配列を格納するためのポインタ配列を動的に確保
    char **strings = (char **)malloc(numStrings * sizeof(char *));
    for (int i = 0; i < numStrings; i++) {
        strings[i] = (char *)malloc(maxLength * sizeof(char));
        // 文字列を初期化
        strcpy(strings[i], "Sample");
    }
    // 配列の内容を出力
    for (int i = 0; i < numStrings; i++) {
        printf("%s\n", strings[i]);
    }
    // メモリの解放
    for (int i = 0; i < numStrings; i++) {
        free(strings[i]);
    }
    free(strings);
    return 0;
}

この例では、3つの文字列を格納するために動的にメモリを確保し、使用後に解放しています。

メモリリークの防止

メモリリークを防ぐためには、確保したメモリを必ず解放することが重要です。

動的に確保したメモリを解放しないと、プログラムが終了するまでメモリが使用されたままになり、システムのリソースを無駄に消費します。

  • 確保したメモリは、使用が終わったらfree関数で解放する。
  • 確保したメモリのポインタを失わないように、ポインタの管理に注意する。

動的メモリ確保の利点と欠点

動的メモリ確保には、いくつかの利点と欠点があります。

スクロールできます
利点欠点
必要なメモリを実行時に柔軟に確保できるメモリリークのリスクがある
メモリの使用効率を向上できるメモリ管理が複雑になる
大規模なデータを扱う際に便利メモリ確保に失敗する可能性がある

動的メモリ確保を使用することで、プログラムの柔軟性が向上しますが、メモリ管理の責任がプログラマに委ねられるため、注意が必要です。

特に、メモリリークを防ぐための適切なメモリ解放が重要です。

応用例

文字列のソート

文字列の2次元配列をソートすることで、アルファベット順や辞書順に並べ替えることができます。

以下の例では、qsort関数を使用して文字列をソートします。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 比較関数
int compareStrings(const void *a, const void *b) {
    return strcmp(*(const char **)a, *(const char **)b);
}
int main() {
    char *fruits[] = {"Banana", "Apple", "Cherry", "Mango", "Peach"};
    int numFruits = sizeof(fruits) / sizeof(fruits[0]);
    // 文字列をソート
    qsort(fruits, numFruits, sizeof(char *), compareStrings);
    // ソート後の配列を出力
    printf("ソートされた果物のリスト:\n");
    for (int i = 0; i < numFruits; i++) {
        printf("%s\n", fruits[i]);
    }
    return 0;
}

このプログラムは、qsort関数を使用して、果物の名前をアルファベット順にソートします。

文字列の検索

文字列の2次元配列から特定の文字列を検索することも可能です。

以下の例では、strcmp関数を使用して文字列を検索します。

#include <stdio.h>
#include <string.h>
int main() {
    char *colors[] = {"Red", "Blue", "Green", "Yellow", "Purple"};
    int numColors = sizeof(colors) / sizeof(colors[0]);
    char *searchColor = "Green";
    int found = 0;
    // 文字列を検索
    for (int i = 0; i < numColors; i++) {
        if (strcmp(colors[i], searchColor) == 0) {
            printf("%sはリストの%d番目にあります。\n", searchColor, i + 1);
            found = 1;
            break;
        }
    }
    if (!found) {
        printf("%sはリストにありません。\n", searchColor);
    }
    return 0;
}

このプログラムは、色のリストから”Green”を検索し、見つかった場合はその位置を出力します。

文字列のフィルタリング

文字列の2次元配列から特定の条件に合致する文字列をフィルタリングすることができます。

以下の例では、特定の文字で始まる文字列をフィルタリングします。

#include <stdio.h>
#include <string.h>
int main() {
    char *cities[] = {"Tokyo", "Osaka", "Nagoya", "Kyoto", "Kobe"};
    int numCities = sizeof(cities) / sizeof(cities[0]);
    char startChar = 'K';
    printf("'%c'で始まる都市:\n", startChar);
    for (int i = 0; i < numCities; i++) {
        if (cities[i][0] == startChar) {
            printf("%s\n", cities[i]);
        }
    }
    return 0;
}

このプログラムは、都市のリストから’K’で始まる都市名をフィルタリングし、出力します。

結果として、”Kyoto”と”Kobe”が出力されます。

よくある質問

文字列の2次元配列とポインタ配列の違いは?

文字列の2次元配列とポインタ配列は、どちらも複数の文字列を格納するために使用されますが、メモリの管理方法に違いがあります。

2次元配列は、メモリが連続して確保されるため、固定サイズの文字列を扱うのに適しています。

一方、ポインタ配列は、各文字列が独立したメモリ領域に格納されるため、異なる長さの文字列を扱うのに適しています。

例:char *words[] = {"Hello", "World"};はポインタ配列です。

文字列の2次元配列のサイズを動的に変更できますか?

文字列の2次元配列のサイズを動的に変更することは直接的にはできません。

C言語では、配列のサイズは固定されているため、動的にサイズを変更するには、動的メモリ確保を使用して新しいメモリ領域を確保し、必要に応じてデータをコピーする必要があります。

例:realloc関数を使用してメモリを再確保することができます。

文字列の2次元配列を使う際の注意点は?

文字列の2次元配列を使用する際には、以下の点に注意が必要です。

  • 各文字列の最大長を適切に設定し、終端文字 \0 のためのスペースを確保する。
  • メモリの確保と解放を適切に行い、メモリリークを防ぐ。
  • 配列の境界を超えないようにアクセスする。

まとめ

文字列の2次元配列は、複数の文字列を効率的に管理するための便利なデータ構造です。

この記事では、文字列の2次元配列の宣言、初期化、操作、メモリ管理、応用例について詳しく解説しました。

これらの知識を活用して、C言語での文字列操作をより効果的に行いましょう。

  • URLをコピーしました!
目次から探す