• ベストアンサー

strchr() の第2引数はなぜ int 型なのでしょうか

jactaの回答

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.9

> 「文字」をメモリの中から区別して表現するためには char では足らない状況があったため、統一的に int を使っているのだと思う、と言うことです。 多バイト文字を除けば、文字を表現するのにcharで足りないという状況はありません。 JIS X3010:2003の6.2.5 型から引用すると... 型charとして宣言されたオブジェクトは, 実行基本文字集合の任意の要素を格納するのに十分な大きさを持つ。実行基本文字集合の任意の要素をchar型のオブジェクトに格納した場合, その値は非負であることを保証する。その他の文字をchar型のオブジェクトに格納した場合, その結果の値は処理系定義とするが, その型で表現可能な値の範囲に含まれなければならない。 となっていることが理由です。 > char は 1byte ですが、マシンの最小処理単位が 1byte ではない環境(ワードマシン)があることが原因じゃないかな、と。 例えば、アドレスが16ビット単位の場合、charを16ビットとして実装するのが普通です。どうしてもcharを8ビットにしたい場合、char*はアドレスのほかにワードの上位か下位かを表すビット情報が含まれることになります。 つまり、これはcharで文字を表現できない理由にはなりません。 > まず 'A' が int と言うのは事実です。 これはその通りです。 C++では'A'はchar型ですが、'AB'のような多文字リテラルはint型になります。 > で、x + y がいったん int になる、と言うのは整数拡張のことを指していると思われます。(これは言語仕様としてはC99からかな?) 整数拡張というよりは「通常の算術型変換」によるものです(通常の算術型変換の過程で整数拡張が行われることがあります)。 整数拡張(integer promotion)という用語はC99のものですが、以前は汎整数拡張(integral promotion)という用語が使われていただけで、内容は同じです。 > が、x = y や関数の引数として char を渡したときに int に拡張される、というのは処理系依存だと思います。 処理系には依存しません。 ちなみに、x + yのときにintに拡張されるかどうかは処理系に依存します。なぜなら、charが符号無しで、charとintのビット数が同じ場合はunsigned intに拡張されるからです。

koko_u_
質問者

お礼

かような重箱の隅をつつく質問に回答いただきありがとうございました。 普段、標準関数は「そういうもんだ」と思って使っていたので、今回改めて勉強になりました。

関連するQ&A

  • sscanf() 関数の第 1 引数の型

     カーニハン/リッチー・著,石田晴久・訳の「プログラミング言語 C・第 2 版」で,「付録 B」にある sscanf() 関数のプロトタイプが   int sscanf(char *s, const char *format, ...) とあって,疑問に思いました。この第 1 引数の型は,「char *」ではなくで「const char *」のほうが合理的のように思えるのです。JIS X 3010-2003 では,const がついていましたし,さまざまな解説・マニュアルでも const つきで示されています。  そこで,ANSI C または JIS X3010-1993 の仕様書をお持ちの方,それらの仕様書の中で sscanf() 関数がどのようなプロトタイプを持っているか,ご教示願えませんでしょうか。ひょっとしたら本当に const がついていないのかもしれないし,書籍から何らかの理由で const が抜け落ちてしまったのかもしれません。  細かい点で恐縮ですが,ご回答くだされば幸いです。

  • C++の問題で困っています。

    C++の問題で困っています。 今,C++の入門書を読んでその中の演習問題に取り組んでいるのですが、この本には答えがついていないみたいなので、問題で悩んでいます。 お力を貸してください。 問題 「文字列 s に含まれる最も先頭に位置する文字 c へのポインタを返す関数 strchr_ptr を作成せよ。型は char * strchr_ptr(const char *s, char c); とする。例えば、文字列 s が "ABSZXYX" で文字 c が 'X' であれば、返却するのは &s[4]である。 なお、文字 c が文字列 s に含まれない場合は NULL を返却すること。 」 です。 僕はこの問題に対して、以下のように答えました。 ヘッダのインクルードなどは省きます。 char *strchr_ptr(const char *s, char c) {         for(int i = 0; s[i]; i++)         if(s[i] == c)             return const_cast<char *>(&s[i]);     return NULL; } int main() {     char s[36] = "ABSZXYX";     cout << strchr_ptr(s, 'X') << "\n";     cout << &s + 4 << "\n"; } と書きました。 cout << &s + 4 << "\n"; はこの上の文で導き出したアドレスがあっているか確かめるものです。 ですが、これをコンパイルして実行すると、 ----------------- XYX 0012FFE0 ----------------- となり、関数側のほうはアドレス的な表記をしてくれません・・。 どうにかして、アドレス表記にしようとあれこれ考えたのですが、どうしても出来ませんでした。 どのようにしたらいいのか教えてください。 初歩的な質問ですが、よろしくお願いします。

  • 文字列リテラルの比較について

    下記のプログラムの疑問点を教えて頂きたい。 (1)mainの実引数(ch[0]は、str_chr関数を呼ぶ場合、intの型変更する理由、 (2)cをキヤストしてchar 型変更した後、再度int C に代入する理由 (3)char型*Sとint 型Cでは、型が違うのに何故比較できる理由 char *str_chr(const char *s, int c) { c = (char)c; while (*s != c) { } main { char ch[2]; str_chr(G,ch[0]) main {

  • qsortの引数について

    以下のプログラムがあります。 int compare( const char **name1, const char **name2 ) { return strcmp( *name1, *name2 ); } int main( void ) { char *names[] = { "rand", "calloc", "malloc" }; int num = sizeof names / sizeof names[0]; qsort( names, num, sizeof( names[0] ), (int (*)(const void *, const void * ))compare ); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~この部分 return 0; } 上の「~~~」の上の部分のqsort関数の第4引数のキャストの意味が 分かりません。なぜ関数の前に引数が書かれるのでしょうか? またintの後にある(*)は「int型のポインタ」と言う意味なのか、 compare関数のポインタなのかも分かりません。 ご回答よろしくおねがいします。

  • C言語のint型の配列が分かりません

    #include<stdio.h> int main(void) { int str[ ]={0,1,2} printf("%s\n", str); return 0; } というプログラムをC言語でつくってみましたが動きません.(012と表示されて欲しかったのですが) int str[ ]={1,2,3}の部分をchar str[ ]={'0','1','2'}とすれば動きます. そこで質問なのですが, printf("~%s~", (配列名));  はchar型の配列にしか適応できないのですか? ※追記 puts関数の定義は int puts (const char *str); であるそうなので char型の仮引数にはchar型のアドレスを渡さなければいけません. ではprintf関数の定義は一体どんなものなのですか?

  • 関数プロトタイプ無しで、引数が float の場合

    またまた float がらみでつまずています。 以下のようなソース(2つのファイルに分割されています)を実行すると、 f = 2.000000 と表示されました。 test1.c で、func() のプロトタイプを書いてないのが諸悪の根源だとは思うのですが(警告もでています)プロトタイプの役割は、 ・引数の型の不整合がないようにする ・必要に応じて、仮引数と実引数の型変換を発生させる だと思います。 このソースでは(たまたまですが)引数の型もあっているので、正常に実行できそうな気がするのですが、なぜ、結果がおかしくなってしまうのでしょうか。 確かに、プロトタイプがないのは好ましくはないですが。 test1.c に、int func(float f); を追加したときには、確かに f = 0.010000 と表示されます。 また、f と func() の引数を double にしたときには、プロトタイプがなくても、正常に実行されます。 ----- test1.c ------------- int main() { float f = 0.01; func(f); return 0; } ----- test2.c ------------- #include <stdio.h> int func(float f) { printf("f = %f", f); return 0; } ----- ここまで ------------

  • ポインタと文字列(C言語)

    サンプルソース char *myfgets(char *s, int n, FILE *in){-----(1) int ch; while((ch = fgetc(in)) != '\n'){ if(ch == EOF) return NULL; *s++ = ch; if(*s == (n - 1))------(2) return NULL; } *s++ = '\n'; *s = '\0'; return s; } 自分でfgets関数を作ろうという課題なのですがポインタがいまいちつかめません。 (1)のchar *myfgetsの部分の関数のポインタというのは要するにどういうことに使うのでしょうか? (2)の場合の*sは配列の要素数を表しているのでしょうか?

  • int main(int argc, char* argv[]) についての質問

    こんにちは.つね日ごろ思っている質問させてください. Cの参考書には, (1) void main(void) { } (2) int main(int argc, char* argv[]) { return 0; } の2つのパターンが記載されていますが, どういう違いがあるのでしょうか? (1)の場合main関数は,型を持たず,引数も持たない. ※Turbo Cなどのコンパイラーでは, return文がないと警告出ます. (2)の場合は,int 型をかえし,引数はint型 変数と char型ポインタ配列(?) を指定している. といったくらいしか分かりません. (2)に関してもう少し述べれば, コマンドラインからファイルを指定し,実行することが できると勉強した記憶があるのですが, 理解があいまいです. 特に(2)の場合のmain関数の意味と,その使い方について アドバイスお願い致します.

  • main の引数には const 付けた方が

    C言語での質問です。 引数を取るような main 関数は int main( int argc, char *argv[]){~} とされていますが、argvの指す文字列を変更する、というのはいくら何でもまずいので、 int main( int argc, const char *argv[]){~} あるいは int main( int argc, const char const * const * argv){~} の方がいいのではないでしょうか? 何故、constを付けない形が出回っているのでしょうか?

  • 'const char *' 型は 'char *' 型に変換できない ??

    Case 1 Text9.Text = "AB"; Text10.Text = "A"; // 1文字目 Text11.Text = "B"; // 2文字目 case 2; Text9.Text = "Ab"; Text10.Text = "A"; Text11.Text = "b"; case 3; Text9.Text = "aB"; Text10.Text = "a"; Text11.Text = "B"; case 4; Text9.Text = "ab"; Text10.Text = "a"; Text11.Text = "b"; 上記のようなCase 文を C を使って作成したいのですが, A~J の大文字とa~jまでの小文字をつかって,2文字の文字列をつくるとき, 1文字目と2文字目が,形態も名称も異なる文字列(例 AB , Ab aB, ab, AC, Ac aC ac, ...)のcase文をつくりたいのですが, 'const char *' 型は 'char *' 型に変換できないというエラーメッセージがでてしまいます.下記プログラムをどう直せばいいかおしえてください. #include <stdio.h> #define MAX_NAME 256 int main(void) { const char *NAME12 = "Text9"; const char *NAME1 = "Text10"; const char *NAME2 = "Text11"; const char *ALPH = "ABCDEFGHIJabcdefghij"; FILE *fp = NULL; char f_name[MAX_NAME]; int count = 0; char *p = ALPH; char *q = ALPH; printf("ファイル名:"); scanf("%s", f_name); fp = fopen(f_name, "w"); if (fp == NULL) { printf("'%s':ファイルが見つかりません\n", f_name); } else { for (p = ALPH; *p != '\0'; p++) { for (q = ALPH; *q != '\0'; q++) { if (*p != *q) { count++; fprintf(fp, "Case %d\n", count); fprintf(fp, "%s.Text = \"%c%c\"\n", NAME12, *p, *q); fprintf(fp, "%s.Text = \"%c%c\"\n", NAME1, *p, *q); fprintf(fp, "%s.Text = \"%c%c\"\n", NAME2, *p, *q); } } } fclose(fp); } return 0; }