当日の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\>