当日のOHP資料です。
11.文字列とポインタ( Text p.248 - 265 )
Download : sample-001.c ( SJIS 版 )
#include <stdio.h> int main ( void ) { int index; char *pstr; /* 「文字列リテラル」は、(名前がつけられていない..)文字配列の先頭を指すポインター値を表す */ printf ( "\"abc\" + 1 == \"%s\"\n", "abc" + 1 ); /* ポインター値なので「計算」できる */ for ( index = 0; index < 4; index++ ) { /* 配列として扱う事もできる(ポインター値だから) */ printf ( "\"abc\"[%d]==%x ('%c')\n", index, "abc"[index], "abc"[index] ); } printf ( "sizeof ( \"abc\" ) == %d\n", sizeof ( "abc" ) ); printf ( "\n---\n" ); /**/ pstr = "abcxyz"; /* ポインター変数の値にできる */ printf ( "pstr == %s\n", pstr ); printf ( "sizeof ( pstr ) == %d\n", sizeof ( pstr ) ); printf ( "\n---\n" ); /**/ // pstr[1] = 'B'; // エラーになった... /* 値の書き換えも ... ? */ // printf ( "pstr == %s\n", pstr ); /* 定数へのポインター値 */ return 0; }
C:\usr\c\> sample-001 "abc" + 1 == "bc" "abc"[0]==61 ('a') "abc"[1]==62 ('b') "abc"[2]==63 ('c') "abc"[3]==0 (' ') sizeof ( "abc" ) == 4 --- pstr == abcxyz sizeof ( pstr ) == 4 --- C:\usr\c\>
Download : sample-002.c ( SJIS 版 )
#include <stdio.h> #define ARRAY_SIZE 1024 #define EOS '\0' /* 文字列と文字配列 */ int main ( void ) { char carray [ ARRAY_SIZE ]; /* 文字配列 */ printf ( "sizeof ( char ) == %d\n", sizeof ( char ) ); printf ( "ARRAY_SIZE == %d\n", ARRAY_SIZE ); printf ( "sizeof ( carray ) == %d\n", sizeof ( carray ) ); printf ( "\n---\n" ); /**/ carray[0] = 'a'; /* 文字配列(carray)上に「文字列("abc")」を実現する */ carray[1] = 'b'; carray[2] = 'c'; carray[3] = EOS; /* 最後に EOS が必要 */ printf ( "carray==\"%s\"\n", carray ); printf ( "sizeof ( carray ) == %d\n", sizeof ( carray ) ); /* 「文字配列のサイズ」と「文字列の長さ」は無関係 */ printf ( "strlen ( carray ) == %d\n", strlen ( carray ) ); /* 「文字列の長さ」は、strlen 関数で求める */ printf ( "\n---\n" ); /**/ carray[1] = EOS; printf ( "carray==\"%s\"\n", carray ); printf ( "sizeof ( carray ) == %d\n", sizeof ( carray ) ); /* 「文字配列のサイズ」は、いつも同じ */ printf ( "strlen ( carray ) == %d\n", strlen ( carray ) ); /* 「文字列の長さ」は、状況で変化する */ printf ( "carray[2] == '%c'\n", carray[2] ); /* EOS 以後の内容は「文字列」上は無視される */ carray[1] = 'B'; printf ( "carray==\"%s\"\n", carray ); printf ( "\n---\n" ); /**/ printf ( "\"ab\\0cd\" == \"%s\"\n", "ab\0cd" ); printf ( "sizeof ( \"ab\\0cd\" ) == %d\n", sizeof ( "ab\0cd" ) ); printf ( "strlen ( \"ab\\0cd\" ) == %d\n", strlen ( "ab\0cd" ) ); printf ( "\"ab\\0cd\"[3] == '%c'\n", "ab\0cd"[3] ); /* 「文字列」表現は、実際には「初期化済の文字配列」を表現している */ /**/ return 0; }
C:\usr\c\> sample-002 sizeof ( char ) == 1 ARRAY_SIZE == 1024 sizeof ( carray ) == 1024 --- carray=="abc" sizeof ( carray ) == 1024 strlen ( carray ) == 3 --- carray=="a" sizeof ( carray ) == 1024 strlen ( carray ) == 1 carray[2] == 'c' carray=="aBc" --- "ab\0cd" == "ab" sizeof ( "ab\0cd" ) == 6 strlen ( "ab\0cd" ) == 2 "ab\0cd"[3] == 'c' C:\usr\c\>
Download : sample-003.c ( SJIS 版 )
#include <stdio.h> #include <string.h> #define ARRAY_SIZE 1024 #define EOS '\0' int main ( void ) { char carray [ ARRAY_SIZE ]; /* strcpy : 文字列の内容の Copy を行うライブラリ関数 */ strcpy ( carray, "abcxyz" ); printf ( "carray==\"%s\"\n", carray ); printf ( "strlen ( carray ) ==%d\n", strlen ( carray ) ); /* 領域が重なる場合は注意が必要 */ strcpy ( carray, carray + 1 ); printf ( "carray==\"%s\"\n", carray ); /* 以下のプログラムは適切には動かない (why ? : 考えてみよう.. ) */ // strcpy ( carray + 1, carray ); // printf ( "carray==\"%s\"\n", carray ); /* 領域が重なる場合は memmove を使う */ /* もはや「文字列」ではなく、「文字配列」として扱う必要がある */ strcpy ( carray, "abcxyz" ); memmove ( carray + 1, carray, strlen ( carray ) + 1 ); printf ( "carray==\"%s\"\n", carray ); return 0; }
C:\usr\c\> sample-003 carray=="abcxyz" strlen ( carray ) ==6 carray=="bcxyz" carray=="aabcxyz" C:\usr\c\>
Download : sample-004.c ( SJIS 版 )
#include <stdio.h> #include <string.h> #define ARRAY_SIZE 1024 #define EOS '\0' int main ( void ) { char carray [ ARRAY_SIZE ]; char *find; /* strcpy : 文字列の内容を Copy する */ /* Copy される先が十分な大きさの領域を持つ事は、strcpy を呼ぶ側の人間の責任 */ /* strcpy には、先頭の「ポインター値」しか渡さない (サイズを知る手段はない) */ strcpy ( carray, "abc" ); /* carray == "abc" */ printf ( "carray == \"%s\"\n", carray ); /* strcat : 文字列の内容を後に「追加」する */ /* Copy される先が十分な大きさの領域を持つ事は、strcpy を呼ぶ側の人間の責任 */ /* strcpy には、先頭の「ポインター値」しか渡さない (サイズを知る手段はない) */ strcat ( carray, "xyz" ); /* carray == "abcxyz" */ printf ( "carray == \"%s\"\n", carray ); /* 置き換えるのは、「内容」なので、一部分を差し替える事もできる (が EOS まで Copy される事に注意) */ strcpy ( carray + 4, "123456" ); /* carray == "abcx123456" */ printf ( "carray == \"%s\"\n", carray ); strcpy ( carray + 2, "PQR" ); /* carray == "abPQR", "abPQR23456" ではない */ printf ( "carray == \"%s\"\n", carray ); /* strcat を strcpy と strlen で表現できる */ strcpy ( carray + strlen ( carray ), "?!" ); /* carray == "abPQR?!" と、追加される */ printf ( "carray == \"%s\"\n", carray ); return 0; }
C:\usr\c\> sample-004 carray == "abc" carray == "abcxyz" carray == "abcx123456" carray == "abPQR" carray == "abPQR?!" C:\usr\c\>
Download : sample-005.c ( SJIS 版 )
#include <stdio.h> #include <string.h> #define ARRAY_SIZE 1024 #define EOS '\0' int main ( void ) { char carray [ ARRAY_SIZE ]; char darray [ ARRAY_SIZE ]; char *parray; /**/ strcpy ( carray, "abc" ); strcpy ( darray, "abc" ); parray = carray; /**/ printf ( "carray = %p\n", carray ); printf ( "darray = %p\n", darray ); printf ( "parray = %p\n", parray ); /* parray == carray */ /* ポインター値は比較する事ができる */ if ( parray == carray ) { printf ( "parray == carray\n" ); } else { printf ( "parray != carray\n" ); } if ( parray == darray ) { printf ( "parray == darray\n" ); } else { printf ( "parray != darray\n" ); } /**/ if ( !strcmp ( carray, parray ) ) { /* 等しいと 0 になる */ printf ( "carray(\"%s\") == parray(\"%s\")\n", carray, parray ); } else { printf ( "carray(\"%s\") != parray(\"%s\")\n", carray, parray ); } if ( !strcmp ( darray, parray ) ) { /* 「内容」が同じなら 0 になる */ printf ( "darray(\"%s\") == parray(\"%s\")\n", darray, parray ); } else { printf ( "darray(\"%s\") != parray(\"%s\")\n", darray, parray ); } if ( !strcmp ( "abc", parray ) ) { /* 比較対象は文字リテラルでもよい */ printf ( "\"%s\" == parray(\"%s\")\n", "abc", parray ); } else { printf ( "\"%s\" != parray(\"%s\")\n", "abc", parray ); } /**/ strcpy ( darray, "XYZ" ); if ( !strcmp ( darray, parray ) ) { /* 「内容」が違えば 0 以外になる */ printf ( "darray(\"%s\") == parray(\"%s\")\n", darray, parray ); } else { printf ( "darray(\"%s\") != parray(\"%s\")\n", darray, parray ); } /* strcmp は文字列の比較に利用される */ printf ( "\"%s\" > \"%s\" なら strcmp ( \"%s\", \"%s\" ) = %d > 0\n", "pqr", "xyz", "pqr", "xyz", strcmp ( "pqr", "xyz" ) ); printf ( "\"%s\" < \"%s\" なら strcmp ( \"%s\", \"%s\" ) = %d < 0\n", "abc", "pqr", "abc", "pqr", strcmp ( "abc", "pqr" ) ); return 0; }
C:\usr\c\> sample-005 carray = 0xbfd5f31c darray = 0xbfd5ef1c parray = 0xbfd5f31c parray == carray parray != darray carray("abc") == parray("abc") darray("abc") == parray("abc") "abc" == parray("abc") darray("XYZ") != parray("abc") "pqr" > "xyz" なら strcmp ( "pqr", "xyz" ) = -1 > 0 "abc" < "pqr" なら strcmp ( "abc", "pqr" ) = -1 < 0 C:\usr\c\>
Download : sample-006.c ( SJIS 版 )
#include <stdio.h> #include <string.h> #define ARRAY_SIZE 1024 #define EOS '\0' int main ( void ) { char carray [ ARRAY_SIZE ]; char *find; /* strstr 部分文字列の位置を求める関数 */ strcpy ( carray, "123abc456abc789" ); find = strstr ( carray, "abc" ); if ( find != NULL ) { /* 見付かった場合は、その位置を表すポインター値 */ printf ( "%s の中に%sがあり、%s の所です\n", carray, "abc", find ); } else { /* 見付からなかった場合は、「何も差さない事が保証されている」NULL ポインター値 */ printf ( "%s の中に%sがありません\n", carray, "abc" ); } find = strstr ( carray, "xyz" ); if ( find != NULL ) { printf ( "%s の中に%sがあり、%s の所です\n", carray, "xyz", find ); } else { printf ( "%s の中に%sがありません\n", carray, "xyz" ); } return 0; }
C:\usr\c\> sample-006 123abc456abc789 の中にabcがあり、abc456abc789 の所です 123abc456abc789 の中にxyzがありません C:\usr\c\>
Download : sample-007.c ( SJIS 版 )
#include <stdio.h> #include <string.h> #define ARRAY_SIZE 1024 #define EOS '\0' int main ( void ) { char carray [ ARRAY_SIZE ]; char *find; /* strchr : 部分文字列の位置を求める関数 */ strcpy ( carray, "123abc456abc789" ); find = strchr ( carray, 'a' ); if ( find != NULL ) { /* 見付かった場合は、その位置を表すポインター値 */ printf ( "%s の中に%cがあり、%s の所です\n", carray, 'a', find ); } else { /* 見付からなかった場合は、「何も差さない事が保証されている」NULL ポインター値 */ printf ( "%s の中に%cがありません\n", carray, 'a' ); } find = strchr ( carray, 'x' ); if ( find != NULL ) { printf ( "%s の中に%cがあり、%s の所です\n", carray, 'x', find ); } else { printf ( "%s の中に%cがありません\n", carray, 'x' ); } return 0; }
C:\usr\c\> sample-007 123abc456abc789 の中にaがあり、abc456abc789 の所です 123abc456abc789 の中にxがありません C:\usr\c\>
Download : sample-008.c ( SJIS 版 )
#include <stdio.h> #include <string.h> #define ARRAY_SIZE 1024 #define EOS '\0' /* 「後文字列」形式の strcmp */ int after_strcmp_sub ( char *btop, int bindex, char *ttop, int tindex ) { if ( btop[bindex] != ttop[tindex] ) { /* 先頭の文字が異なれば、結果は解る */ return btop[bindex] - ttop[tindex]; } else { /* 先頭の文字が同じならば、まだ調べる必要がある */ if ( btop[bindex] == EOS ) { /* 共に EOS なら、"" (空文字列) 同士なので等しい */ return 0; } else { /* そうでなければ残りを調べる */ return after_strcmp_sub ( btop, bindex + 1, ttop, tindex + 1 ); } } } int after_strcmp ( char *base, char *target ) { return after_strcmp_sub ( base, 0, target, 0 ); } /* ポインター形式の strcmp */ int pointer_strcmp_sub ( char *bptr, char *tptr ) { if ( *bptr != *tptr ) { /* <btop,bindex> == (btop+bindex) == bptr */ return *bptr - *tptr; } else { if ( *bptr == EOS ) { return 0; } else { return pointer_strcmp_sub ( bptr + 1, tptr + 1 ); /* <btop,bindex+1> = (btop+(bindex+1)) == (btop+bindex)+1 == bptr + 1 */ } } } int pointer_strcmp ( char *base, char *target ) { return pointer_strcmp_sub ( base, target ); /* <base,0> == base, <target,0> == target */ } /* */ int main ( void ) { /* after_strcmp */ printf ( "after_strcmp :\n" ); printf ( "\"%s\" > \"%s\" なら after_strcmp ( \"%s\", \"%s\" ) = %d > 0\n", "abc", "abp", "abc", "abp", after_strcmp ( "abc", "abp" ) ); printf ( "\"%s\" < \"%s\" なら after_strcmp ( \"%s\", \"%s\" ) = %d < 0\n", "abx", "abp", "abx", "abp", after_strcmp ( "abx", "abp" ) ); printf ( "\"%s\" = \"%s\" なら after_strcmp ( \"%s\", \"%s\" ) = %d = 0\n", "abp", "abp", "abp", "abp", after_strcmp ( "abp", "abp" ) ); /* pointer_strcmp */ printf ( "pointer_strcmp :\n" ); printf ( "\"%s\" > \"%s\" なら pointer_strcmp ( \"%s\", \"%s\" ) = %d > 0\n", "abc", "abp", "abc", "abp", pointer_strcmp ( "abc", "abp" ) ); printf ( "\"%s\" < \"%s\" なら pointer_strcmp ( \"%s\", \"%s\" ) = %d < 0\n", "abx", "abp", "abx", "abp", pointer_strcmp ( "abx", "abp" ) ); printf ( "\"%s\" = \"%s\" なら pointer_strcmp ( \"%s\", \"%s\" ) = %d = 0\n", "abp", "abp", "abp", "abp", pointer_strcmp ( "abp", "abp" ) ); return 0; }
C:\usr\c\> sample-008 after_strcmp : "abc" > "abp" なら after_strcmp ( "abc", "abp" ) = -13 > 0 "abx" < "abp" なら after_strcmp ( "abx", "abp" ) = 8 < 0 "abp" = "abp" なら after_strcmp ( "abp", "abp" ) = 0 = 0 pointer_strcmp : "abc" > "abp" なら pointer_strcmp ( "abc", "abp" ) = -13 > 0 "abx" < "abp" なら pointer_strcmp ( "abx", "abp" ) = 8 < 0 "abp" = "abp" なら pointer_strcmp ( "abp", "abp" ) = 0 = 0 C:\usr\c\>
[問題] 2010/11/05の「後文字列」を利用して実現されている三つのProgram (sample-009 [ sjis 版],sample-011 [ sjis 版],sample-013 [ sjis 版] )を、ポインターを用いて書き換えなさい。
課題プログラム内の「/*名前:ここ*/」の部分を書き換えてプログラムを完成させます。なお「名前」の部分が同じ所には同じものが入ります。
Download : 20101210-01.c ( SJIS 版 )
/* * 文字列の長さ [ 再帰版 ] */ #include <stdio.h> /* */ #define EOS '\0' /* * substr_length : 後文字列の長さを求める (再帰版) */ unsigned int substr_length ( /* q:ここ */ ) { if ( /* p:ここ */ == EOS ) { /* 空文字列 */ return 0; /* 長さは 0 */ } else { return substr_length ( /* r:ここ */ ) + 1; /* 更に後文字列の長さを求めて 1 ふやす */ } } /* * str_length : 文字列の長さを求める (後部分列を利用する) */ unsigned int str_length ( const char str[] ) { return substr_length ( /* o:ここ */ ); /* str 自身の長さは、後部分文字列 <str,0> の長さに等しい */ } /* * main */ #define STRING_LENGTH 127 #define STRING_SIZE (STRING_LENGTH+1) int main ( void ) { char str[STRING_SIZE]; int i; printf ( "文字列を入力してください : " ); scanf ( "%127s", str ); printf ( "文字列「%s」の長さは%uです。\n", str, str_length ( str ) ); return 0; }
SEC
C:\usr\c\> 20101210-01 文字列を入力してください : SEC 文字列「SEC」の長さは3です。 C:\usr\c\>
Download : 20101210-02.c ( SJIS 版 )
/* * 文字列の走査 [ 再帰版 ] */ #include <stdio.h> /* */ #define EOS '\0' /* * put_substring : 後部分文字列を表示する */ void put_substring ( /* p:ここ */ ) { if ( /* q:ここ */ != EOS ) { /* 空文字列でない */ putchar ( /* q:ここ */ ); /* 先頭の文字を出力し.. */ put_substring ( /* r:ここ */ ); /* 残りは再帰で処理 */ } /* EOS なら空文字列 "" なので何もしなくてもよい */ } /* * put_string : 文字列を表示する(改行しない) */ void put_string ( const char str[] ) { put_substring ( /* o:ここ */ ); /* str の出力は <str,0> の出力 */ } /* * main */ #define STRING_LENGTH 127 #define STRING_SIZE (STRING_LENGTH+1) int main ( void ) { char str[STRING_SIZE]; int i; printf ( "文字列を入力してください : " ); scanf ( "%127s", str ); put_string ( str ); putchar ( '\n' ); return 0; }
SEC
C:\usr\c\> 20101210-02 文字列を入力してください : SEC SEC C:\usr\c\>
Download : 20101210-03.c ( SJIS 版 )
/* * 文字列内の数字の個数を数える [ 再帰版 ] */ #include <stdio.h> /* */ #define EOS '\0' /* * _substr_dcount : 後部分文字列内の数字の個数をそれぞれ求める */ void substr_dcount ( /* p:ここ */, int cnt[] ) { if ( /* q:ここ */ != EOS ) { cnt[/* q:ここ */-'0']++; substr_dcount ( /* r:ここ */, cnt ); } } /* * _str_dcount : 文字列内の数字の個数をそれぞれ求める */ void str_dcount ( const char str[] , int cnt[] ) { substr_dcount ( /* o:ここ */, cnt ); } /* * main */ #define STRING_LENGTH 127 #define STRING_SIZE (STRING_LENGTH+1) int main ( void ) { char str[STRING_SIZE]; int cnt[ '9' - '0' + 1 ] = {0}; /* '0' 〜 '9' で 10 文字 (植木算に注意) */ int digit; printf ( "文字列を入力してください : " ); scanf ( "%127s", str ); str_dcount ( str, cnt ); for ( digit = '0'; digit <= '9'; digit++ ) { printf ( "'%c' : %d\n", digit, cnt[ digit - '0'] ); } return 0; }
3.1415926532897265
C:\usr\c\> 20101210-03 文字列を入力してください : 3.1415926532897265 '0' : 0 '1' : 2 '2' : 3 '3' : 2 '4' : 1 '5' : 3 '6' : 2 '7' : 1 '8' : 1 '9' : 2 C:\usr\c\>