Powered by SmartDoc

ソフトウェア概論B (2010/12/10)
Ver. 1.0

2010年12月10日
栗野 俊一
kurino@math.cst.nihon-u.ac.jp
http://edu-gw2.math.cst.nihon-u.ac.jp/~kurino/2010/soft/soft.html
ソフトウェア概論 B2010年12月10日 の資料

目次

講義資料

当日の OHP 資料

当日のOHP資料です。

本日の概要

11.文字列とポインタ( Text p.248 - 265 )

講義で利用するサンプルプログラム

sample-001

Download : sample-001.c ( SJIS 版 )

sample-001.c
#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;
}
sample-001.c の実行結果
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\> 

sample-002

Download : sample-002.c ( SJIS 版 )

sample-002.c
#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;
}
sample-002.c の実行結果
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\> 

sample-003

Download : sample-003.c ( SJIS 版 )

sample-003.c
#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;
}
sample-003.c の実行結果
C:\usr\c\> sample-003
carray=="abcxyz"
strlen ( carray ) ==6
carray=="bcxyz"
carray=="aabcxyz"
C:\usr\c\> 

sample-004

Download : sample-004.c ( SJIS 版 )

sample-004.c
#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;
}
sample-004.c の実行結果
C:\usr\c\> sample-004
carray == "abc"
carray == "abcxyz"
carray == "abcx123456"
carray == "abPQR"
carray == "abPQR?!"
C:\usr\c\> 

sample-005

Download : sample-005.c ( SJIS 版 )

sample-005.c
#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;
}

	
sample-005.c の実行結果
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\> 

sample-006

Download : sample-006.c ( SJIS 版 )

sample-006.c
#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;
}

	
sample-006.c の実行結果
C:\usr\c\> sample-006
123abc456abc789 の中にabcがあり、abc456abc789 の所です
123abc456abc789 の中にxyzがありません
C:\usr\c\> 

sample-007

Download : sample-007.c ( SJIS 版 )

sample-007.c
#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;
}
sample-007.c の実行結果
C:\usr\c\> sample-007
123abc456abc789 の中にaがあり、abc456abc789 の所です
123abc456abc789 の中にxがありません
C:\usr\c\> 

sample-008

Download : sample-008.c ( SJIS 版 )

sample-008.c
#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;
}
sample-008.c の実行結果
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 版] )を、ポインターを用いて書き換えなさい。

課題プログラム内の「/*名前:ここ*/」の部分を書き換えてプログラムを完成させます。なお「名前」の部分が同じ所には同じものが入ります。

課題 20101210-01

Download : 20101210-01.c ( SJIS 版 )

20101210-01.c
/*
 * 文字列の長さ [ 再帰版 ]
 */

#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
20101210-01.c の実行結果
C:\usr\c\> 20101210-01
文字列を入力してください : SEC
文字列「SEC」の長さは3です。
C:\usr\c\> 

課題 20101210-02

Download : 20101210-02.c ( SJIS 版 )

20101210-02.c
/*
 * 文字列の走査 [ 再帰版 ]
 */

#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
20101210-02.c の実行結果
C:\usr\c\> 20101210-02
文字列を入力してください : SEC
SEC
C:\usr\c\> 

課題 20101210-03

Download : 20101210-03.c ( SJIS 版 )

20101210-03.c
/*
 * 文字列内の数字の個数を数える [ 再帰版 ]
 */

#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
20101210-03.c の実行結果
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\>