「C言語/中級者向けの話題」の版間の差分

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
s/構造体の型枠/構造体/、{{コラム|配列の一括代入}}
タグ: 2017年版ソースエディター
28 行
の <syntaxhighlight lang="c" inline>sizeof a / sizeof *a</syntaxhighlight> は、「配列の要素数」を得る時のイデオムです。
 
{{コラム|配列の一括代入|2=この節で触れたように、C言語では配列同士の代入は出来ません。が、構造体同士の代入はできます。
== 関数 ==
この事と、キャストを組み合わせると。
main関数には大まかに分けてプログラム仮引数(コマンドライン引数)を持たない関数と持つ関数との2種類の記述方法がある。
 
;[https://paiza.io/projects/1IRaexWbl0IHeGZdtj-wzg?language=c 強引な配列の一括代入]:<syntaxhighlight lang="c" line>
=== 仮引数 ===
#include <stdio.h>
==== 仮引数とは何か ====
 
コマンドラインから実行ファイル名などを入力してプログラムを実行する際、実行ファイルに文字列データを渡すことができる。
int main() {
int a[] = {2, 3, 5, 7, 11},
b[sizeof a / sizeof *a];
struct Dummy { int dmy[sizeof a / sizeof *a] };
*(struct Dummy *)b = *(struct Dummy *)a;
printf("b[3] = %d\n", b[3]);
}</syntaxhighlight>
の様に要素1つの構造体の代入として実現できます。
 
}}
 
== main関数 ==
プログラム起動時に呼び出される関数はmainと名付けられています。実装では,この関数のプロトタイプを宣言しない。この関数は,戻り値の型がintで,パラメータがない状態で定義されなければならない。
int main(void) { /* ... */ }
または2つのパラメータ(ここではargcとargvとしていますが、宣言された関数のローカルなものなので、どのような名前を使っても構いません)を持つものです。
int main(int argc, char *argv[]) { /* ... */ }
またはそれと同等の方法で、またはその他の実装で定義された方法による<ref name="jtc1-sc22-wg14-n2596-5.1.2.2.1">{{cite book
| url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/c17_updated_proposed_fdis.pdf
| archiveurl = https://web.archive.org/web/20181230041359/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf
| archivedate = 2018-12-30
| title = N2176 C17 ballot ISO/IEC 9899:2017
| page = 10, §5.1.2.2.1 ''Program startup''
| publisher = ISO/IEC JTC1/SC22/WG14}}</ref>。
* argc の値は非負でなければならない。
* argv[argc]はヌルポインターとする。
* argcの値が0より大きい場合、配列メンバargv[0]~argv[argc-1]には、プログラムの起動前にホスト環境によって実装定義された値を持つ文字列へのポインタが格納される。この目的は、ホスト環境の他の場所からプログラム起動前に決定された情報をプログラムに供給することである。<!--
-->ホスト環境が大文字と小文字の両方の文字を持つ文字列を供給できない場合、実装は文字列が小文字で受信されるようにしなければならない。
* argc の値が 0 より大きい場合、argv[0] が指す文字列はプログラム名を表す。<!--
-->argv[0][0]には、ホスト環境からプログラム名が得られない場合は、ヌル文字を指定する。<!--
-->argv[0][0]はヌル文字とする。argc の値が 1 より大きい場合は、argv[1]~argv[argc-1]が指す文字列がプログラム仮引数(''program parameters''; 一般にコマンドライン引数)を表す。
* パラメータ argc、argv および argv 配列が指す文字列は、プログラムによって変更可能であり、プログラムの起動から終了までの間、最後に保存された値を保持する。
 
 
www.DeepL.com/Translator(無料版)で翻訳しました。
 
=== プログラム仮引数 ===
==== プログラム仮引数とは何か ====
コマンドラインから実行ファイル名などを入力してプログラムを実行する際、実行ファイルに文字列データを渡すことができます。
 
方法は、コンパイル後に、単にコマンド入力で、たとえば
39 ⟶ 79行目:
のように、ファイル名の後ろに、渡したい文字列を書けばいい。(上記コマンドの場合なら文字列「moji」が渡される)
 
このように、実行ファイル自体に対して渡される情報を、プログラム仮引数と呼ぶ。(なお「プログラム仮引数」自体の意味は、単になんらかの関数の定義側で書かれた引数のことであり、実行ファイルとは関係ない。)
 
例えばコマンドプロンプトにおいて、
52 ⟶ 92行目:
 
 
プログラム仮引数を利用するには、ソースコードのmain関数に
 
<syntaxhighlight lang="C">
63 ⟶ 103行目:
この順番を守ること。
 
第一引数の整数型の引数は、コマンドライン入力時の単語の数である。(実行ファイル名も単語1個ぶんとして数える。)
 
たとえばコマンド入力が
75 ⟶ 115行目:
:argv[1]は 「ABC」 であり、
:argv[2]は 「DEF」 であり、
:argv[3]は 「GHI」 である
 
 
;コード例:<syntaxhighlight lang="C">
下記コードは、実行時に「ja」と追記することで、日本語で「こんにちは」とアイサツをするプログラムである。単に実行ファイル名だけを入力した場合、英語で「hello」と答える。
 
<syntaxhighlight lang="C">
#include "stdio.h"
#include "string.h"
111 ⟶ 148行目:
</syntaxhighlight>
のように入力すれば、日本語で「こんにちは」と答える。
 
==== 詳細 ====
===== プログラム仮引数を持つ関数 =====
プログラム仮引数を使用する場合、次のように2つの仮引数をもつ関数を記述する。
 
<syntaxhighlight lang="C">
int main(int argc, char *argv[])
{
/*いくつかの文*/
}
</syntaxhighlight>
 
:argcはプログラム仮引数の個数である。
:argvはプログラム仮引数を表す文字列の配列へのポインタである。
:argv[0]が指す文字列はプログラム名である。
:argcにはこのプログラム名も個数として数えられる。
 
ただし、argcが0の場合、argv[0]は空ポインタである。
またargc>0であっても、ホスト環境からプログラム名が得られない場合、
argv[0]は空ポインタである。
<ref>『[迷信] argv[0] はプログラム名 | 株式会社きじねこ』http://www.kijineko.co.jp/tech/superstitions/argv0-is-program-name.html</ref>
argv[1]からargv[argc-1]までが指す文字列は、プログラム仮引数である。
argv[argc]は空ポインタである。
<ref>『JISX3010:2003』p.8「5.1.2.2.1 プログラム開始処理」</ref>
 
<syntaxhighlight lang="C">
//例 プログラム仮引数
#include <stdio.h>
 
int main(int argc, char *argv[])
{
for (int i = 0; i < argc; i++) {
printf("argv[%d]の値 : %s\n", i, argv[i]);
}
}
</syntaxhighlight>
 
 
===== プログラム仮引数を持たせない場合 =====
プログラム仮引数を使用したくない場合には、単に下記のように main 関数の引数を void あるいは空白にすればいいだけである。こうすれば、仮引数をもたないとして処理される。
 
<syntaxhighlight lang="C">
int main(void)
{
/*いくつかの文*/
}
</syntaxhighlight>
 
 
=== 関数の実行環境 ===
220 ⟶ 209行目:
=== 関数指定子 ===
==== inline関数指定子 ====
inline関数指定子は、関数の宣言だけで使用できます
inline関数指定子は、その関数の呼び出しを可能な限り速くすることを示唆しま
この示唆が効果をもつ程度は、処理系定義としま
<ref>『JISX3010:2003』p.83「6.7.4 関数指定子」</ref>
 
259 ⟶ 248行目:
関数へのポインタとは、
ある関数のメモリアドレスを格納し、
その関数に間接的にアクセスする方法である
関数へのポインタは、
次のような場合に使われる。
291 ⟶ 280行目:
関数へのポインタを使って、
間接的に関数を呼び出すには、
次のように記述しま
 
<syntaxhighlight lang="C">
347 ⟶ 336行目:
 
==== 再帰 ====
再帰(さいき)とは、ある関数がその関数自身を呼び出すことである
 
典型的な用途として、数学の階乗(5×4×3×2×1のような計算)などが、よくあげられる。
353 ⟶ 342行目:
再帰に向いた計算に再帰を使うと、ソースコードを簡潔に書ける場合がある。
 
ただし、再帰ではハードウェア資源的には弱点があり、スタックのためにメモリを多く占有するので負担になるという弱点もある。そのため、再帰で桁数の多すぎる計算などをすると、与えられたスタック領域を使いはたてしまうと異常終了などのエラーを引きおこす場合もある。これは、いわゆる「スタック・オーバーフロー」(stack overflow)というエラーの一種である
 
再帰では、
431 ⟶ 420行目:
ビットフィールドとは、
1ビット以上のビットからなる、
構造体のメンバの一種である
ビットフィールドを用いると、
1ビット以上のビットに名前をつけ、
その名前でアクセスできます
 
ビットフィールドは、構造体の型枠を宣言する時メンバとして次のように記述しま
<syntaxhighlight lang="C">
データ型 メンバ名:サイズ;
</syntaxhighlight>
 
データ型は、(signed) intまたはunsigned intを指定しま
(signed) intを指定すると、上位ビットが符号として扱われる。
メンバ名とサイズとを「:(コロン)」で区切る。
サイズはそのメンバを何ビットで表すかを指定しま
 
;ビットフィールド:<syntaxhighlight lang="C">
470 ⟶ 459行目:
bits.bit8 = 0;
 
printf("bitsのメンバの値は、%d %d %d %d %d %d %d %dです。\n", bits.bit1,
bits.bit2, bits.bit3, bits.bit4, bits.bit5, bits.bit6, bits.bit7,
bits.bit8);
477 ⟶ 466行目:
</syntaxhighlight>
;結果:<syntaxhighlight lang="text">
bitsのメンバの値は、1 0 1 0 1 0 1 0です。
bitsのサイズは、1です。
</syntaxhighlight>