文字列

授業中にカバーできなかったら、冬休みの宿題。期末テストに類似の問題、出します。

文字

シンボルをシングルクオートで囲って、文字を表す。

char c;

c = 'a';

文字列は char の配列

文字が複数個繋がったもの、"hello" や "日本語" などを文字列という。 文字列の間にスペース文字や改行文字が含まれることもある。

C 言語では文字列を表現するのに要素の型が char の配列を使う。 そして、文字列の後ろにヌル文字という特別な文字でマーキングする。 ヌル文字は '\0' で表す。ヌル文字の実体はすべてのビットが 0 のデータ。

char str[10];   // 長めに配列を用意する。

str[0] = 'h';   // 配列要素に文字を代入していく。
str[1] = 'e';
str[2] = 'l';
str[3] = 'l';
str[4] = 'o';
str[5] = '\0';  // 文字列の終わりをマーク。str[5] = 0; でもよい。
str[6] = 'z';   // ヌル文字の後ろは文字列の一部とは認識されない。

printf("%s\n", str); // %s がデータを文字列と解釈する決まり。hello とプリントされる。そして改行。zは無視される。

文字と文字列を区別すること

文字データは、シンボルを シングルクオート ' ' で囲む。

  • 'a', 'b', '0','!','\n','\0' はすべて文字。'\n'は改行、'\0' はヌル文字。

  • 'abc' はエラー。

文字列は 0 個以上のシンボルの続きを ダブルクオート " " で囲む。

  • "a" ...先頭に 'a' が入った長さ1の文字列。配列の2番目にはヌル文字'\0'。

    'a''\0'

  • "abc" ... char配列の先頭に'a', 2番目に 'b', 3番目に'c',4番目には '\0'。

    'a''b''c''\0'

  • "a b c" ... 'a', ' ', 'b', ' ', 'c' の5文字からなる文字列。

    'a'' ''b'' ''c''\0'

  • "abc\ndef\n" ... abcの後ろで改行、defの後ろで改行。

    'a''b''c''\n''d''e''f''\n''\0'

  • "" ... 先頭に'\0'が入ったヌル文字列。空文字列。

文字列を初期化する

char s1[10] = "abc"; // s1[0] に 'a', s1[1] に 'b', s1[2] に 'c', s1[3] に '\0' が代入される。
                     // それより後ろはゴミ。
char s2[] = "abc";   // 'a', 'b', 'c', '\0' を格納するに必要十分な要素数 4 つの配列 s2 が用意され、
                     // 各文字が各場所に代入される。

文字列を scanf で読み込む

入力が予想される文字列の長さ以上の char 型配列を用意しておき、 scanf("%s", 配列の名前) で、 入力中に空白文字が現れるまで の文字列を配列に読み込む。

char str[10];
scanf("%s", str); // キーボードから abc def ghi と打つと変数 str には "abc" が読み込まれる。

準備した配列の長さ以上の文字列を scanf で読むと予期しないエラーになる。 コンピュータウィルスの侵入口のひとつ。


ここから以下はすべて個人課題。 文字列を操作する関数を作ってみることは C 言語のいいトレーニングになる。

できない問題はグループ、あるいはグループを超えて話し合ってよい。 個人課題の提出を済ますことより、自分の理解度にプライドをもて。

文字列の長さを求める

文字列の最後の後ろには必ずヌル文字 '\0' がある。 配列の先頭から数えて '\0' が何番目にあるかを求め、 その番号を戻り値とする関数を定義すればよい。

// 文字列 s の長さ(文字列中の文字数)を返す。
int str_len(char s[])
{
    int i;
    for (i = 0; _______; i++) {
        ;
    }
    return i;
}
  • 文字列 "1234567" の長さを str_len( ) で求めよ。
  • 文字列 "I am a programmer." の長さを str_len( )で求めよ。

文字列に含まれる特定の文字を数える

// 戻り値は文字列 str 中の文字 c の出現回数。
int count_chars(char str[], char c)
{
    int i;
    int count = 0;
    for (i = 0; str[i] != '\0'; i++) {
        if (str[i] == c) {
            count++;
        }
    }
    return _____;
}
  • 文字列 "sumomomo momo mo momo no uchi" に文字 'o' は何個含まれるか?

二つの文字列が等しいかどうかを判定する

文字列 s1 と s2 とが同じ文字列かどうかは == で判定できない。次のプログラムでそれを確かめろ。

#include <stdio.h>
int main(void)
{
    char s1[] = "abcdef";
    char s2[] = "abcdef";

    if (s1 == s2) {
        printf("equal\n");
    } else {
        printf("not equal\n");
    }
}
イコールにならない理由は上記のコードは配列 s1 と配列 s2 のアドレスを比較するから。
アドレスわからなくてもプログラミングできます。
この授業ではアドレス、ポインタ、扱いません。

二つの文字列が等しいとは、文字列に含まれる文字が全て同じってこと。 二つの文字列が等しければ 1、等しくなければ 0 を返す関数 str_eql(s1, s2) を定義する。

// 文字列 s1 と s2 が等しければ 1、そうでなければ 0 を返す。
int str_eql(char s1[], char s2[])
{
    int i;
    for (i = 0; s1[i] != '\0'; i++) {
        if (s1[i] != s2[i]) {
            return 0;
        }
    }
    return ____________;
}
  • str_sql("abc", "abc") が 1 を返し、 str_eql("abcd", "abc") も str_eql("abc","abcd") も 0 を返すことを確認せよ。
  • 端末から文字列を二つ読み込み、それらが文字列として等しければ、"same"、等しくなければ "not same" をプリントする関数を上で定義した str_eql( ) を下請け関数として作れ。

二つの文字列の先頭から n 文字が等しいかどうかを判定する

プログラマの繊細さが問われる。

// 文字列 s1 と s2 の先頭から n 文字を比較する。
int str_eql_n(char s1[], char s2[], int n)
{
    int i;
    for (i = 0; i < n; i++) {
        if (s1[i] != s2[i]) {
            return 0;
        }
        if (__________________) { // 添字が範囲を超えてないかのチェック
            return 0;
        }
    }
    return 1;
}
  • 文字列 "powerfull" と文字列 "powerless" の先頭から 5 文字を比較し、 等しければ "OK"、等しくなければ "NG" をプリントせよ。
  • str_eql_n("powerfull", "powerless",6) が 0 を返すことを確認せよ。
  • str_eql_n("a","a",100) が 0 を返すことを確認せよ。

文字列 s1 を 文字列 s2 にコピーする

// 文字列 s2 の要素数は s1 の要素数よりも大きいこと。
void str_copy(char s1[], char s2[])
{
    int i;
    for (i = 0; s1[i] != '\0'; i++) {
        s2[i] = s1[i];
    }
    ______________;
}

コピーする文字数よりも s2 に確保している配列の要素数が短いと致命的なエラーになる。 上はまだ不十分。エラーを防ぐにはどうすれば?

  1. char s1[10] = "yoshino";
  2. char s2[10] = "kobayashi";
  3. 文字列 s1 を文字列 s2 にコピーしろ。
  4. 文字列 s1 と文字列 s2 は等しい文字列となったか?

文字列 s1 の後ろに 文字列 s2 をつなぐ

文字列 s1 は s2 をつなぐ十分な長さがあること (十分大きな配列として宣言されていること)が前提。 A を取る気の学生は以下の定義では、 str_append("abc", "xyz")がエラーになることを理解するまで考えること。 考えに考えてもわからないときは 214 室まで。

// 文字列 s1 の後ろに文字列 s2 を付け足す。
void str_append(char s1[], char s2[])
{
    int i;
    for (i = 0; s1[i] != '\0'; i++) {
        ;
    }
    int j;
    for (j = 0; s2[j] != '\0'; j++) {
        s1[i] = s2[j];
        i++;
    }
    ___________;
}
  1. 文字列 s1 を "nakajima" とせよ。
  2. 文字列 s2 を "love" とせよ。
  3. 文字列 s1 の後ろに文字列 s2 をつなげ。
  4. s1 の後ろにスペースを一つ入れ、結果が "nakajima love" となるようにするにはどうすれば?

文字列 s1 の n 文字目からの m 文字を s2 にコピーする。

コピーに成功したら 1, 失敗したら 0 を返そう。

int str_take(char s1[], int n, int m, char s2[])
{
    int i;
    int j = 0;
    for (i = n; i < n + m; i++) { // 不十分。s1 の長さよりも n が大きかったら?
        if (s1[i] == '\0') {
            return 0;
        } else {
            s2[j] = s1[i];
        }
    }
    _________;
    return 1;
}
  • 文字列 "son of a bitch." の 7 文字めから 5 文字を取り出した文字列をプリントせよ。

文字列 s1 中に文字列 s2 が出現するかどうかを判定する

目的の文字を見つけたら s1 の何文字目から出現しているか、 その添え字を返そう。見つからなかった時は添字としてありえない -1 を返そう。

// 文字列 s1 中に文字列 s2 が見つかればその位置、ないときは -1 を返す。
int str_search(char s1[], char s2[])
{
    int i;
    for (i = 0; s[i] != '\0'; i++) {
        if (___________) {
            return i;
        }
    }
    __________;
}
  • 文字列 "fukushima, love and peace" 中に文字列 "love" は何文字目から出現するか。 また、"lovely" は出現するか?

文字列 s1 の n 文字目からの m 文字を削除する

ノーヒントで。

void str_remove(char s1[], int n, int m)
{

}
  • str_remove("Ucchi does not love.", 7, 9); の結果が "Ucchi love." となることを確認せよ。

文字列 s1 中から文字列 s2 を削除する

今度は範囲ではなく、見つかった文字列を削除。

void str_remove_str(char s1[], char s2[])
{

}
  • str_remove_str("Yuki does not love every day.", "not "); の結果が "Yuki does love every day." となることを確認せよ。

文字列 s1 の n 文字目に文字列 s2 を挿入する

できるかな?

void str_insert(char s1[], int n, char s2[])
{

}
  • char s1[100]="He studies hard."; str_insert(s1, 11, "very ")); により、 s1 が "He studies very hard." となることを確認せよ。

文字列 s1 中に現れる文字列 s2 を文字列 s3 で置き換える

このくらいできれば配列、文字列は合格。C言語の理解もだいぶ深まったはず。

void str_subst(char s1[], char s2[], char s3[])
{

}
  • char s1[100]="All you need is XX."; とし、 str_subst(s1, "XX", "love") の呼び出しにより s1 が "All you need is love."となることを確認せよ。
  • str_subst(s1, "YYY", "hate") の呼び出しで s1 が変化しないことを確認せよ。

できない問題はグループ、あるいはグループを超えて話し合ってよい。 個人課題の提出を済ますことより、自分の理解度にプライドをもて。

index


hkimura.

1.0.2