[前へ]   [目次へ]   [次へ]

文字列を扱う関数(C/C++)


   (10/01/06) sscanf関数の戻り値を訂正

今回からは単語当てゲームLv1を作っていきます。
作ろうとしているゲームの概要は 前回 をご覧いただくとして、
これまでに「文字列の入力」「乱数の生成」などは既に行っています。

そして新登場なのは「文字列制御」です。
今回は文字列制御のために用意されているC言語標準の関数についてです。

言語標準で用意されている文字列制御用の関数は、あまり多くの機能を持ちません。
どちらかというと基本的な機能を持つものばかりで、使い方はプログラマに任されています。

また、イロイロと注意事項が多いのも文字列系関数の特徴で、ちょっと間違えるとすぐバグります。
理由はここまでの内容を元に考えれば分かるかと思いますが、
C/C++言語の文字列の扱いは「終端文字まで」という扱い方なので、終端文字がなかったりすると即暴走です。
受け入れ可能なサイズを指定しない関数も結構数があるので、領域違反も要注意です。

さて、今回は文字列にまつわる関数の紹介です。

まずは主要どころから。
ヘッダは「使うために #include するヘッダ名」です。
関数名ヘッダ機能
sprintfstdio.hデータを書式化してメモリに書き込みます
sscanfstdio.h文字列から書式化されたデータを読み込みます
strcatstring.h文字列を結合します
strcmpstring.h文字列を比較します
strcpystring.h文字列をコピーします
strlenstring.h文字列の長さを取得します
strchrstring.h文字列から1文字を検索します
strstrstring.h文字列から文字列を検索します
strncatstring.h文字列を結合します
strncmpstring.h文字列を比較します
strncpystring.h文字列をコピーします

そして、以下はメモリ領域を扱う関数であって、文字列関数ではないのですが、
仕様が似ていることから「違いがよくわからない」という壁を与えがちな関数です。
せっかくなのでここでこれらもまとめて解説します。
でも仕様時点で既にstring.h(文字列関数用ヘッダ)に入っている謎。
個人的にはコレstdlib.hの方がしっくりくるんですけど・・・

関数名ヘッダ機能
memchrstring.h指定したメモリエリアから1バイトを検索します
memcmpstring.h指定したメモリエリアを比較します
memcpystring.h指定したメモリエリアに指定バイトをコピーします(領域の重複禁止)
memmovestring.h指定したメモリエリアに指定バイトをコピーします(領域の重複可)
memsetstring.h指定したメモリエリアを指定値で埋めます

他にもまだあるんですが、とりあえず上記の関数が一通り使えれば大体のことはできます。
実際、これら以外の標準文字列関数、私ほとんど使いません(笑)
時々、strtokを勧める人がいますけど、仕様が使いづらいので私は嫌いなんです(笑)


御覧の通り、文字列関数のほとんどは string.h にあります。
今回紹介していない文字列関数も、大半が string.h にあります。
上記の中で特に使い勝手がいいのが sprintf sscanf strlen memcpy memset の5個。
これらは機能的に便利な上、比較的注意事項が扱いやすいので重宝します。

それでは、仕様をざっくり見ていきます。
仕様の終端へ

●sprintf

プロトタイプ宣言:
int sprintf(char *buffer,const char *format,...)

printf 関数と同じフォーマット指定を使って、文字列を整形します。
この関数は printf 関数の出力先を第1引数( buffer )に変更したものであり、
第2引数( format )は printf 関数の第1引数と同じです。

戻り値: buffer 文字列配列に出力したバイト数(ナル文字分を除く)を返します。

引数:
char* buffer :[出力]生成した文字列の書き込み先になる配列へのポインタ(絶対ID)。
const char* format :生成するフォーマット指定を格納した、文字列配列へのポインタ(絶対ID)。
                                 指定方法は printf 関数と同じ。
以降略(可変長引数):フォーマット指定で指定された引数を必要数だけ記述します。

注意事項:
buffer のサイズは確認しません。
   生成する文字列が buffer に収まることは呼び出し元が保証する必要があります。
format はナル終端文字列でなければいけません。
format の指定と適合しない引数を与えた場合の結果は不定です。

使用例:
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
#include <stdio.h>

int main(void){
   
char str[256];
   sprintf(str,
"今回のプログラミング講座は %d 回目です。",70);
   puts(str);
   
return 0;
実行結果:
今回のプログラミング講座は 70 回目です。



●sscanf

プロトタイプ宣言:
int sscanf(const char *buffer,const char *format,...)

これは以前にも解説したことがありますね。
scanf 関数と同じフォーマット指定を使って、文字列を解析します。
この関数は scanf 関数の入力元を第1引数( buffer )に変更したものであり、
第2引数( format )は scanf 関数の第1引数と同じです。

(10/01/06赤字部分訂正)
戻り値: buffer の文字列を変換した上で、 第3引数以降に指定したポインタを介して書き込んだ数を返します。
      読み捨て指定された要素は数えません。
      変換に失敗した場合、エラーが発生した場合は EOF を返します。

引数:
const char* buffer :解析する文字列配列へのポインタ(絶対ID)。
const char* format :解析するフォーマット指定を格納した、文字列配列へのポインタ(絶対ID)。
                                 指定方法は scanf 関数と同じ。
以降略(可変長引数):フォーマット指定で指定された引数を必要数だけ記述します。

注意事項:
buffer format はナル終端文字列でなければいけません。
format の指定と適合しない引数を与えた場合の結果は不定です。

使用例:
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
#include <stdio.h>

int main(void){
   
char str[64]="30 50 70";
   
int n1,n2,n3;
   sscanf(str,
"%d %d %d",&n1,&n2,&n3);
   printf(
"解析結果はn1=%d n2=%d n3=%d でした。\n",n1,n2,n3);
   
return 0;
実行結果:
解析結果はn1=30 n2=50 n3=70 でした。



●strcat/strncat

プロトタイプ宣言:
char* strcat(char *string1,const char *string2)
char* strncat(char *string1,const char *string2,size_t count)


string1 に string2 を結合します。結果は string1 を上書きします。

strcat 関数と strncat 関数の違いは「書きこみ上限バイト数( count )」を指定するかしないかです。
strcat 関数は string1 が示す配列には string2 を追加できる十分な大きさがある前提で動作します。
strncat 関数は string1 が示す配列には count バイトを追加できる大きさがある前提で動作します。

戻り値:両方とも、 string1 を返します。

引数:
char* string1 :[入出力]結合する左側および出力先の文字列配列へのポインタ(絶対ID)。
const char* string2 :結合する右側の文字列へのポインタ(絶対ID)。
size_t count :[ strncat ] string1 に書き足すことができるバイト数。

注意事項:
strcat :結合後の文字列が string1 が示す配列に収まることは呼び出し元が保証する必要があります。
strncat : string1 が示す配列には count バイト以上の余裕があることは呼び出し元が保証する必要があります。
strcat/strncat : string1 はナル終端文字列でなければいけません。
strcat : string2 はナル終端文字列でなければいけません。
strncat : string2 がナル文字に到達するか、 count バイト進むまでの絶対IDは有効でなければいけません。
strcat/strncat : string1 と string2 が重複する領域を指す場合の結果は未定義(どうなるかわからない)です。

使用例:
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
< 17>
#include <stdio.h>
#include <string.h>

int main(void){
   
char str1[256]="abcde";
   
char str2[256]="abcde";
   
   strcat(str1,
"fghij");
   puts(
"strcatの結果:(abcdeにfghijが結合しました)");
   puts(str1);
   
   strncat(str2,
"fghij",3);
   puts(
"strncatの結果:(countよりもstring2の方が長かったので3文字だけ追加されました)");
   puts(str2);
   
   
return 0;
実行結果:
strcatの結果:(abcdeにfghijが結合しました)
abcdefghij
strncatの結果:(countよりもstring2の方が長かったので3文字だけ追加されました)
abcdefgh




●strcmp/strncmp/memcmp

プロトタイプ宣言:
int strcmp(const char *string1,const char *string2)
int strncmp(const char *string1,const char *string2,size_t count)
int memcmp(const void *buf1,const void *buf2,size_t count)


第1引数が示す情報と第2引数が示す情報を比較し、小さい、同じ、大きいの結果を返します。

strcmp 関数は string1 と string2 をナル終端文字列へのポインタとして、両方の文字列を比較します。
strncmp 関数は string1 と string2 をナル終端文字列へのポインタとして、
      count バイトを上限として両方の文字列を比較します。
      最初の count バイトまたはナル文字までが一致すれば、結果は「同じ」が返されます。
memcmp 関数は buf1 と buf2 が示す絶対IDからの count バイトを比較します。

strcmp 関数と strncmp 関数の違いは比較するバイト数上限を指定するかどうかです。
strcmp/strncmp 関数と memcmp 関数の違いはナル文字を考慮するかどうかです。
前者はナル文字を見つけるとそこで比較を終了しますが、後者は指定バイト数をキッチリ比較します。

戻り値:以下の表に準じます。ただし大小比較よりは一致検証(0かどうかを見る)に主に使用されます。
戻り値意味
<0(負値)第1引数<第2引数
0同じ
>0(正値)第1引数>第2引数

引数:
const char* string1 :[ strcmp/strncmp ]比較する文字列1へのポインタ(絶対ID)。
const char* string2 :[ strcmp/strncmp ]比較する文字列2へのポインタ(絶対ID)。
size_t count :[ strncmp ]比較する最大バイト数
const void* buf1 :[ memcmp ]比較する領域1へのポインタ(絶対ID)。
const void* buf2 :[ memcmp ]比較する領域2へのポインタ(絶対ID)。
size_t count :[ memcmp ]比較するバイト数

注意事項:
strcmp : string1 string2 はナル終端文字列でなければいけません。
strncmp : string1 か string2 がナル文字に到達するか、 
   string1 string2 から count バイト進むまでの絶対IDは有効でなければいけません。
memcmp : buf1 buf2 から count バイトの範囲は有効な絶対IDの範囲でなければいけません。

使用例:
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
< 17>
< 18>
< 19>
< 20>
< 21>
< 22>
< 23>
< 24>
< 25>
< 26>
< 27>
< 28>
< 29>
< 30>
< 31>
< 32>
< 33>
< 34>
< 35>
< 36>
< 37>
< 38>
#include <stdio.h>
#include <string.h>

int main(void){
   
char str1[256]="abcdef23";
   
char str2[256]="abcde1234567890";
   
   
//↓一致すると0(偽)を返すので、真偽反転(!)を使うと一致した時のみ真になります。
   //↓"abcdef23"と"abcde1234567890"は一致しません。
   
if(!strcmp(str1,str2))puts("strcmp:一致しました。");
   
else puts("strcmp:異なりました。");
   
   
//↓最初の5バイトまでなので"abcde"と"abcde"を比較し、一致します。
   
if(!strncmp(str1,str2,5))puts("strncmp:一致しました。");
   
else puts("strncmp:異なりました。");
   
   
//↓最初の5バイトまでなので"abcde"と"abcde"を比較し、一致します。
   
if(!memcmp(str1,str2,5))puts("memcmp:一致しました。");
   
else puts("memcmp:異なりました。");
   
   puts(
"文字列を5文字目で切ります");
   str1[5]=
'\0';
   str2[5]=
'\0';
   
//↓"abcde"と"abcde"は一致します。
   
if(!strcmp(str1,str2))puts("strcmp:一致しました。");
   
else puts("strcmp:異なりました。");
   
   
//↓10バイトまでですが、文字列は10バイトより短いので
   //  "abcde"と"abcde"を比較し、一致します。
   
if(!strncmp(str1,str2,10))puts("strncmp:一致しました。");
   
else puts("strncmp:異なりました。");
   
   
//↓しっかり10バイトなので、"abcde\023\0\0"と"abcde\02345"を比較し、一致しません。
   
if(!memcmp(str1,str2,10))puts("memcmp:一致しました。");
   
else puts("memcmp:異なりました。");
   
   
return 0;
実行結果:
strcmp:異なりました。
strncmp:一致しました。
memcmp:一致しました。
文字列を5文字目で切ります
strcmp:一致しました。
strncmp:一致しました。
memcmp:異なりました。




●strcpy/strncpy/memcpy/memmove

プロトタイプ宣言:
char* strcpy(char *dst,const char *src)
char* strncpy(char *dst,const char *src,size_t count)
void* memcpy(void *dst,const void *src,size_t count)
void* memmove(void *dst,const void *src,size_t count)


dst に src をコピーします。結果は dst を上書きします。

strcpy 関数と strncpy 関数の違いは「書きこみ上限バイト数( count )」を指定するかしないかです。
strcpy 関数は dst が示す配列には src の文字列をコピーできる十分な大きさがある前提で動作します。
strncpy 関数は dst が示す配列には count バイトをコピーできる大きさがある前提で動作します。
   ただし、 strncpy 関数は count の制限によって処理を終了した場合、ナル文字を出力しません。
   そのため、ナル文字がない状態を放置しないように注意しなければなりません。
strncpy
 関数は count バイト進む前に src からナル文字を検出した場合、 count バイト分までナル文字を埋めます。

strcpy/strncpy 関数と memcpy/memmove 関数の違いはナル文字を考慮するかどうかです。
前者はナル文字を見つけるとそこで src からのコピーを終了しますが、後者は指定バイト数を確実にコピーします。

memcpy 関数と memmove 関数の違いはコピー範囲の重複を認めるかどうかです。
memcpy 関数はコピー元とコピー先の両方に同じ絶対IDが含まれる場合の結果が保証されません
      (正しくコピーするかもしれないし、しないかもしれない)が、
memmove 関数はコピー元の情報をコピー先に確実にコピーします。(そのかわり memmove 関数は若干遅い)

戻り値:全て、 dst を返します。

引数:
char* dst :[ strcpy/strncpy ][出力]出力先の文字列配列へのポインタ(絶対ID)。
const char* src :[ strcpy/strncpy ]コピー元の文字列へのポインタ(絶対ID)。
size_t count :[ strncpy/memcpy/memmove ] dst に書き込むバイト数。
void* dst :[ memcpy/memmove ][出力]出力先の領域へのポインタ(絶対ID)。
const void* dst :[ memcpy/memmove ]コピー元の領域へのポインタ(絶対ID)。

注意事項:
strcpy : src が示す文字列が dst に収まることは呼び出し元が保証する必要があります。
strncpy : dst が示す配列が count バイト以上の大きさであることは呼び出し元が保証する必要があります。
strncpy : src が示す文字列が count バイト以上の長さの場合、ナル文字は付与されません。
strcpy : src はナル終端文字列でなければいけません。
strncpy : src がナル文字に到達するか、 count バイト進むまでの絶対IDは有効でなければいけません。
memcpy/memmove : src dst から count バイト進むまでの絶対IDは有効でなければいけません。
strcpy/strncpy/memcpy : dst と src が重複する領域を指す場合の結果は未定義(どうなるかわからない)です。

使用例:
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
< 17>
< 18>
< 19>
< 20>
< 21>
< 22>
< 23>
< 24>
< 25>
< 26>
< 27>
< 28>
< 29>
< 30>
< 31>
< 32>
< 33>
< 34>
< 35>
< 36>
< 37>
< 38>
< 39>
< 40>
< 41>
< 42>
< 43>
< 44>
< 45>
< 46>
< 47>
#include <stdio.h>
#include <string.h>

int main(void){
   
char str1[256]="abcdefghij1234567890";
   
char str2[256]="klmnoあいうえお";
   
char str3[256]="abcdefghij1234567890";
   
   strcpy(str1,str2);
   puts(
"strcpyの結果:(str1にstr2をコピーしました)");
   puts(str1);
   
   str1[15]=
'p';//str2をコピーした時に設定されたナル文字を消します
   
puts("strcpy(ナル文字削除後)の結果:(コピーしたナル文字を消したので、残りが出てきました)");
   puts(str1);
   
   strncpy(str2,
"pqrst",3);
   puts(
"strncpyの結果:(countよりもsrcの方が長かったのでナル文字が付与されませんでした)");
   puts(
"               そのため、元の文字列の残りが表示されています");
   puts(str2);
   
   str2[3]=
'\0';//ナル文字を追加
   
puts("strncpy(ナル文字追加後)の結果:(ナル文字を付けたので3文字になりました)");
   puts(str2);
   
   memcpy(str3,str2,11);
   puts(
"memcpyの結果:(str3にstr2を11バイトコピーしました)");
   puts(str3);
   
   str3[3]=
'u';//さっき追加したナル文字を消します
   
puts("memcpy(ナル文字削除後)の結果:(strcpyと違い、11バイトしっかりコピーされています)");
   puts(str3);
   
   strcpy(str3,
"abcdefghij1234567890");//str3を元に戻します
   
   
memcpy(&(str3[10]),str3,20);//10バイト先に20バイトコピーします(領域重複)
   
puts("memcpy(領域重複)の結果:(妙なことになっています)");
   puts(str3);
   
   strcpy(str3,
"abcdefghij1234567890");//str3を元に戻します
   
   
memmove(&(str3[10]),str3,20);//10バイト先に20バイトコピーします(領域重複)
   
puts("memmoveの結果:(領域重複でも正しくコピーしています)");
   puts(str3);
   
   
return 0;
実行例:
strcpyの結果:(str1にstr2をコピーしました)
klmnoあいうえお
strcpy(ナル文字削除後)の結果:(コピーしたナル文字を消したので、残りが出てきました)
klmnoあいうえおp7890
strncpyの結果:(countよりもsrcの方が長かったのでナル文字が付与されませんでした)
               そのため、元の文字列の残りが表示されています
pqrnoあいうえお
strncpy(ナル文字追加後)の結果:(ナル文字を付けたので3文字になりました)
pqr
memcpyの結果:(str3にstr2を11バイトコピーしました)
pqr
memcpy(ナル文字削除後)の結果:(strcpyと違い、11バイトしっかりコピーされています)
pqruoあいう234567890
memcpy(領域重複)の結果:(妙なことになっています)
abcdefghijabcdefghijabcdefghij
memmoveの結果:(領域重複でも正しくコピーしています)
abcdefghijabcdefghij1234567890




●strlen

プロトタイプ宣言:
size_t strlen(const char *string)

string の文字数(バイト数)を数えます。
結果は戻り値として返されます。
ナル文字の分は含まれません。したがって、 string[strlen(string)] はナル文字になります。

戻り値: string の文字数(バイト数)を返します。

引数:
const char* string :文字数を数える文字列へのポインタ(絶対ID)。

注意事項:
string はナル終端文字列でなければいけません。

使用例:
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
#include <stdio.h>
#include <string.h>

int main(void){
   
char str1[256]="abcde1234567890あいうえお";
   
   printf(
"%sの文字数(バイト数):%d\n",str1,(int)strlen(str1));
   
   
return 0;
実行結果:
abcde1234567890あいうえおの文字数(バイト数):25



●strchr/memchr

プロトタイプ宣言:
char* strchr(const char *string,int c)
void* memchr(const void *buf,int c,size_t count)


strchr 関数は string が示す文字列から c の値を持つバイトを検索し、
最初に見つけた場所のポインタ(絶対ID)を返します。
memchr 関数は buf が示す絶対IDから count バイトの領域中の c の値を持つバイトを検索し、
最初に見つけた場所のポインタ(絶対ID)を返します。
どちらも、見つからなかった場合は NULL を返します。

戻り値:両方とも、見つかった場所へのポインタ(絶対ID)を返します。
      見つからなかった場合は NULL を返します。

引数:
const char* string :[ strchr ]検索対象の文字列へのポインタ(絶対ID)。
int c :検索する値。
const void* buf :[ memchr ]検索対象の領域を示すポインタ(絶対ID)。
size_t count :[ memchr ]検索対象のバイト数。

注意事項:
strchr : string はナル終端文字列でなければいけません。
strchr :通常、日本語文字を解釈しません。日本語第2バイトを拾ってしまう可能性があるので、注意が必要です。
strchr/memchr :引数が const ポインタであり、この領域内のポインタ(絶対ID)を返すにもかかわらず、
            戻り値型は const ポインタではありません。不正な const 外しに注意しなければなりません。
memchr : buf から count バイト進むまでの絶対IDは有効でなければいけません。

使用例:
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
< 17>
< 18>
< 19>
< 20>
< 21>
< 22>
< 23>
< 24>
< 25>
< 26>
< 27>
< 28>
< 29>
< 30>
< 31>
#include <stdio.h>
#include <string.h>

int main(void){
   
char str1[256]="abcde1234567890ソあいうえお";
   
char *ptr;
   
void *ptr2;
   
   ptr=strchr(str1,
'e');//str1に含まれる e を探します
   
if(ptr!=NULL)printf("e 検出位置からの文字列:%s\n",ptr);
   
else puts("e は見つかりません。");
   
   ptr=strchr(str1,
'E');//str1に含まれる E を探します。大文字小文字は区別されます
   
if(ptr!=NULL)printf("E 検出位置からの文字列:%s\n",ptr);
   
else puts("E は見つかりません。");
   
   ptr=strchr(str1,
'\\');//str1に含まれる \ を探します。0x5c問題の発現理由の一つがこういうものです
                           //注:ソの日本語第2バイトは \ と同じです
   
if(ptr!=NULL)printf("\\ 検出位置からの文字列:%s\n",ptr);
   
else puts("\\ は見つかりません。");
   
   ptr2=memchr(str1,
'e',10);//str1から10バイトの範囲内にある e を探します
   
if(ptr2!=NULL)puts("e が見つかりました。");
   
else puts("e は見つかりません。");
   
   ptr2=memchr(str1,
'0',10);//str1は 0 を含みますが、15バイト目にあるので検出されません
   
if(ptr2!=NULL)puts("0 が見つかりました。");
   
else puts("0 は見つかりません。");
   
   
return 0;
実行結果:
e 検出位置からの文字列:e1234567890ソあいうえお
E は見つかりません。
\ 検出位置からの文字列:\あいうえお
e が見つかりました。
0 は見つかりません。




●strstr

プロトタイプ宣言:
char* strstr(const char *string1,const char *string2)

string1 が示す文字列に含まれる string2 が示す文字列を検索します。

戻り値: string1 が示す文字列内に string2 が示す文字列が見つかった場合、
         string1 が示す文字列内の最初に発見された位置へのポインタ(絶対ID)を返します。
         見つからなかった場合、 NULL を返します。

引数:
const char* string1 :検索対象の文字列へのポインタ(絶対ID)。
const char* string2 :検索する文字列へのポインタ(絶対ID)。

注意事項:
string1 string2 はナル終端文字列でなければいけません。
通常、日本語文字を解釈しません。日本語第2バイトを拾ってしまう可能性があるので、注意が必要です。
引数が const ポインタであり、この領域内のポインタ(絶対ID)を返すにもかかわらず、
            戻り値型は const ポインタではありません。不正な const 外しに注意しなければなりません。

使用例:
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
< 17>
< 18>
< 19>
< 20>
< 21>
< 22>
#include <stdio.h>
#include <string.h>

int main(void){
   
char str1[256]="abcde1234567890ソあいうえお";
   
char *ptr;
   
   ptr=strstr(str1,
"56789");//str1に含まれる 56789 を探します
   
if(ptr!=NULL)printf("56789 検出位置からの文字列:%s\n",ptr);
   
else puts("56789 は見つかりません。");
   
   ptr=strstr(str1,
"CDE");//str1に含まれる CDE を探します。大文字小文字は区別されます
   
if(ptr!=NULL)printf("CDE 検出位置からの文字列:%s\n",ptr);
   
else puts("CDE は見つかりません。");
   
   ptr=strstr(str1,
"\\あ");//str1に含まれる \あ を探します。0x5c問題の発現理由の一つがこういうものです
                           //注:ソの日本語第2バイトは \ と同じです
   
if(ptr!=NULL)printf("\\あ 検出位置からの文字列:%s\n",ptr);
   
else puts("\\あ は見つかりません。");
   
   
return 0;
実行結果:
56789 検出位置からの文字列:567890ソあいうえお
CDE は見つかりません。
\あ 検出位置からの文字列:\あいうえお





●memset

プロトタイプ宣言:
void* memset(void *dst,int c,size_t count)

dst が示す絶対IDから count バイトの領域を c の値で埋め尽くします。

戻り値: dst を返します。

引数:
void* dst :[出力]埋め尽くす対象の領域を示すポインタ(絶対ID)。
int c :埋め尽くす値。0〜255の値を指定します。
size_t count :書き込むバイト数。

注意事項:
dst から count バイト進むまでの絶対IDは有効でなければいけません。

使用例:
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
< 17>
< 18>
< 19>
< 20>
< 21>
#include <stdio.h>
#include <string.h>

int main(void){
   
char str1[256]="abcde1234567890";
   
int i,n[10];
   
   memset(str1,
'7',8);//str1の先頭8バイトを文字 7 で埋めます。
   
puts("str1 の先頭8バイトを文字 7 を埋めた結果:");
   puts(str1);
   
   memset(n,0,
sizeof(n));//nに割り当てられた領域をすべて0にします。
   
puts("n の領域をすべて0で埋めた結果:");
   
//↓ここで全て0になることは言語としては保証されていませんが、
   //大抵のコンパイラでは0になります。
   
for(i=0;i<10;i++){
      printf(
"n[%d]:%d\n",i,n[i]);
   }
   
   
return 0;
実行例:
str1 の先頭8バイトを文字 7 を埋めた結果:
777777774567890
n の領域をすべて0で埋めた結果:
n[0]:0
n[1]:0
n[2]:0
n[3]:0
n[4]:0
n[5]:0
n[6]:0
n[7]:0
n[8]:0
n[9]:0




主要な文字列系関数の仕様を紹介してきましたが、
今回の使用例だけでは具体的に使うのは難しいかもしれません。
次回以降は、御題のゲームを作りながら必要に応じてこれらの関数を使っていきます。


ところで、Windowsで使える関数群を解説している「MSDNライブラリ」というサイトが
本家マイクロソフトで運営されています。(サイト名でググれば出ます)
ものすごい数の関数やライブラリが載っているのですが、
数が多すぎる上に書き方にクセのようなものがあり、慣れないと読めないような状態になっています。
とはいえWindowsにおいては公式資料ということになる(はず)なので、
ある程度以上のことをやろうと思うと読まないわけにはいかない事情があります。

MSDNライブラリはVisual Studioの最新版を中心に構成されているので、
マイクロソフト製のコンパイラやライブラリの独自拡張が載っていたりします。
そのような場合には注記がありますので、見落としには注意してください。
(この記事を書いている時点では「必要条件」のところに記述されています。
   言語標準の仕様はANSIと記載されているので、ANSI互換などの表現に注意です)

セキュリティが強化されたバージョン云々というのがよく載っていますが、
セキュリティ強化バージョンは現在全て独自拡張であり、標準仕様ではありません。
(実際、強化バージョンの互換性の項にはANSIの文字は記述されていません)
あとたまに日本語版は誤訳があったり、
翻訳されてないページがあるので、必要だと思ったら英語版の原典を見る必要があります。


[前へ]   [目次へ]   [次へ]

プログラミング講座 総合目次

最終更新 2010/01/06