Cprogramming-quick-guide
C言語-概要
Cは、元々Dennis Mによって開発された汎用の高水準言語です。 RitchieがBell LabsでUNIXオペレーティングシステムを開発します。 Cは、1972年にDEC PDP-11コンピュータに最初に実装されました。
1978年、Brian KernighanとDennis Ritchieは、現在K&R規格として知られているCの最初の公開された記述を作成しました。
UNIXオペレーティングシステム、Cコンパイラ、および基本的にすべてのUNIXアプリケーションプログラムはCで記述されています。 Cは現在、さまざまな理由で広く使用されているプロの言語になっています-
- 簡単に学べる
- 構造化言語
- 効率的なプログラムを生成します
- 低レベルのアクティビティを処理できます
- さまざまなコンピュータープラットフォームでコンパイルできます。
Cに関する事実
- Cは、UNIXと呼ばれるオペレーティングシステムを記述するために発明されました。
- Cは1970年代初期に導入されたB言語の後継です。
- この言語は、1988年に米国規格協会(ANSI)によって正式に制定されました。
- UNIX OSは完全にCで書かれています。
- 今日、Cは最も広く使用され人気のあるシステムプログラミング言語です。
- 最新のソフトウェアのほとんどは、Cを使用して実装されています。
- 現在最も人気のあるLinux OSおよびRDBMS MySQLはCで記述されています。
なぜCを使うの?
Cは当初、システム開発作業、特にオペレーティングシステムを構成するプログラムに使用されていました。 Cは、アセンブリ言語で記述されたコードとほぼ同じ速度で実行されるコードを生成するため、システム開発言語として採用されました。 Cの使用のいくつかの例があります-
- オペレーティングシステム
- 言語コンパイラ
- アセンブラー
- テキストエディタ
- 印刷スプーラー
- ネットワークドライバー
- 現代のプログラム
- データベース
- 言語通訳
- 公益事業
Cプログラム
Cプログラムは3行から数百万行まで変化する可能性があり、拡張子が "" .c "の1つ以上のテキストファイルに書き込む必要があります。たとえば、hello.c。 *"vi" 、 "vim" またはその他のテキストエディターを使用して、Cプログラムをファイルに書き込むことができます。
このチュートリアルは、テキストファイルの編集方法とプログラムファイル内でのソースコードの記述方法を知っていることを前提としています。
C-環境設定
Cプログラミング言語用に環境をセットアップする場合は、コンピューターで使用可能な次の2つのソフトウェアツールが必要です。(a)テキストエディターと(b)Cコンパイラ。
テキストエディタ
これは、プログラムの入力に使用されます。 いくつかのエディターの例には、Windows Notepad、OS Editコマンド、Brief、Epsilon、EMACS、vimまたはviが含まれます。
テキストエディタの名前とバージョンは、オペレーティングシステムによって異なる場合があります。 たとえば、メモ帳はWindowsで使用され、vimまたはviはLinuxまたはUNIXだけでなくWindowsでも使用できます。
エディターで作成するファイルはソースファイルと呼ばれ、プログラムのソースコードが含まれています。 Cプログラムのソースファイルには通常、拡張子「 .c 」が付いています。
プログラミングを開始する前に、1つのテキストエディターを用意し、コンピュータープログラムを作成し、ファイルに保存し、コンパイルして、最後に実行する十分な経験があることを確認してください。
Cコンパイラ
ソースファイルに記述されたソースコードは、プログラムの人間が読めるソースです。 CPUが指定された指示に従って実際にプログラムを実行できるように、機械語に「コンパイル」する必要があります。
コンパイラは、ソースコードを最終的な実行可能プログラムにコンパイルします。 最も頻繁に使用され、無料で利用可能なコンパイラはGNU C/C ++コンパイラです。それ以外の場合は、それぞれのオペレーティングシステムがあればHPまたはSolarisのコンパイラを使用できます。
次のセクションでは、GNU C/C コンパイラをさまざまなOSにインストールする方法について説明します。 GNU gccコンパイラーはCおよびC プログラミング言語の両方で機能するため、C/C ++については引き続き言及します。
UNIX/Linuxでのインストール
*LinuxまたはUNIX* を使用している場合は、コマンドラインから次のコマンドを入力して、GCCがシステムにインストールされているかどうかを確認します-
$ gcc -v
あなたのマシンにGNUコンパイラがインストールされている場合、次のようにメッセージを出力するはずです-
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr .......
Thread model: posix
gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)
GCCがインストールされていない場合は、https://gcc.gnu.org/install/にある詳細な手順を使用して自分でインストールする必要があります。
このチュートリアルはLinuxに基づいて作成されており、指定された例はすべてLinuxシステムのCent OSフレーバーでコンパイルされています。
Mac OSへのインストール
Mac OS Xを使用している場合、GCCを入手する最も簡単な方法は、AppleのWebサイトからXcode開発環境をダウンロードし、簡単なインストール手順に従うことです。 Xcodeをセットアップしたら、C/C ++用のGNUコンパイラを使用できるようになります。
Xcodeは現在、https://developer.apple.com/technologies/tools/[developer.apple.com/technologies/tools/]で入手できます。
Windowsへのインストール
GCCをWindowsにインストールするには、MinGWをインストールする必要があります。 MinGWをインストールするには、MinGWホームページhttp://www.mingw.org/[www.mingw.org]にアクセスし、MinGWダウンロードページへのリンクをたどってください。 MinGW- <バージョン> .exeという名前のMinGWインストールプログラムの最新バージョンをダウンロードします。
Min GWのインストール中に、少なくともgcc-core、gcc-g ++、binutils、およびMinGWランタイムをインストールする必要がありますが、さらにインストールすることもできます。
MinGWインストールのbinサブディレクトリを PATH 環境変数に追加して、コマンドラインでこれらのツールを簡単な名前で指定できるようにします。
インストールが完了すると、Windowsコマンドラインからgcc、g ++、ar、ranlib、dlltool、およびその他のいくつかのGNUツールを実行できるようになります。
C-プログラム構造
Cプログラミング言語の基本的な構成要素を学習する前に、次の章で参照できるように、最低限のCプログラム構造を見てみましょう。
ハローワールドの例
Cプログラムは基本的に次の部分で構成されています-
- プリプロセッサコマンド
- 関数
- 変数
- ステートメントと式
- コメント
「Hello World」という言葉を出力する簡単なコードを見てみましょう-
#include <stdio.h>
int main() {
/*my first program in C*/
printf("Hello, World! \n");
return 0;
}
上記のプログラムのさまざまな部分を見てみましょう-
- プログラムの最初の行_#include <stdio.h> _はプリプロセッサコマンドであり、実際のコンパイルに進む前にstdio.hファイルを含めるようにCコンパイラに指示します。
- 次の行_int main()_は、プログラムの実行が開始されるメイン関数です。
- 次の行/…/はコンパイラによって無視され、プログラムにコメントを追加するために追加されました。 そのため、このような行はプログラムではコメントと呼ばれます。
- 次の行_printf(…)_は、「Hello、World!」というメッセージを引き起こすCで使用可能な別の関数です。画面に表示されます。
- 次の行 return 0; はmain()関数を終了し、値0を返します。
Cプログラムのコンパイルと実行
ソースコードをファイルに保存する方法と、コンパイルして実行する方法を見てみましょう。 以下は簡単な手順です-
- テキストエディターを開き、上記のコードを追加します。
- ファイルを_hello.c_として保存します
- コマンドプロンプトを開き、ファイルを保存したディレクトリに移動します。
- _gcc hello.c_と入力し、Enterキーを押してコードをコンパイルします。
- コードにエラーがない場合、コマンドプロンプトは次の行に移動し、_a.out_実行可能ファイルを生成します。
- ここで、_a.out_と入力してプログラムを実行します。
- 出力_ "Hello World" _が画面に表示されます。
$ gcc hello.c
$ ./a.out
Hello, World!
gccコンパイラがパスにあり、ソースファイルhello.cを含むディレクトリで実行していることを確認してください。
C-基本的な構文
Cプログラムの基本構造を見てきましたので、Cプログラミング言語の他の基本的な構成要素を簡単に理解できます。
Cのトークン
Cプログラムはさまざまなトークンで構成され、トークンはキーワード、識別子、定数、文字列リテラル、またはシンボルのいずれかです。 たとえば、次のC文は5つのトークンで構成されています-
printf("Hello, World! \n");
個々のトークンは-
printf
(
"Hello, World! \n"
)
;
セミコロン
Cプログラムでは、セミコロンはステートメントターミネータです。 つまり、個々のステートメントはセミコロンで終了する必要があります。 1つの論理エンティティの終わりを示します。
以下に2つの異なるステートメントがあります-
printf("Hello, World! \n");
return 0;
コメント
コメントは、Cプログラムのテキストを支援するようなものであり、コンパイラによって無視されます。 以下に示すように、/で始まり、文字/で終了します-
/*my first program in C*/
コメント内にコメントを含めることはできません。また、コメントは文字列または文字リテラル内では発生しません。
識別子
C識別子は、変数、関数、またはその他のユーザー定義項目を識別するために使用される名前です。 識別子は、A〜Z、a〜z、またはアンダースコア「_」で始まり、その後に0個以上の文字、アンダースコア、および数字(0〜9)が続きます。
Cでは、識別子内で@、$、%などの句読点文字を使用できません。 Cは、*大文字と小文字を区別*するプログラミング言語です。 したがって、_Manpower_と_manpower_はCの2つの異なる識別子です。 ここに受け入れ可能な識別子のいくつかの例があります-
mohd zara abc move_name a_123
myname50 _temp j a23b9 retVal
キーワード
次のリストは、Cの予約語を示しています。 これらの予約語は、定数、変数、またはその他の識別子名として使用できません。
auto | else | long | switch |
break | enum | register | typedef |
case | extern | return | union |
char | float | short | unsigned |
const | for | signed | void |
continue | goto | sizeof | volatile |
default | if | static | while |
do | int | struct | _Packed |
double |
Cの空白
コメントが含まれている可能性のある空白のみを含む行は、空白行と呼ばれ、Cコンパイラでは完全に無視されます。
空白は、空白、タブ、改行文字、コメントを記述するためにCで使用される用語です。 空白は、ステートメントの一部を別の部分から分離し、コンパイラーがステートメント内の1つの要素(intなど)がどこで終わり、次の要素が始まるかをコンパイラーが識別できるようにします。 したがって、次のステートメントで-
int age;
コンパイラがそれらを区別できるようにするには、intとageの間に少なくとも1つの空白文字(通常はスペース)が必要です。 一方、次の文で-
fruit = apples + oranges; //get the total fruit
果物と=の間、または=とリンゴの間には空白文字は必要ありませんが、読みやすくするために空白文字を含めることは自由です。
C-データ型
cのデータ型は、異なる型の変数または関数を宣言するために使用される広範なシステムを指します。 変数のタイプによって、ストレージ内で占めるスペースの量と、格納されているビットパターンの解釈方法が決まります。
Cの型は次のように分類することができます-
Sr.No. | Types & Description |
---|---|
1 |
Basic Types これらは算術型であり、さらに(a)整数型と(b)浮動小数点型に分類されます。 |
2 |
Enumerated types これらも算術型であり、プログラム全体で特定の離散整数値のみを割り当てることができる変数を定義するために使用されます。 |
3 |
The type void 型指定子_void_は、使用可能な値がないことを示します。 |
4 |
Derived types それらには、(a)ポインター型、(b)配列型、(c)構造体型、(d)ユニオン型、および(e)関数型が含まれます。 |
配列型と構造体型は、集合型と総称されます。 関数のタイプは、関数の戻り値のタイプを指定します。 次のセクションで基本タイプを確認します。他のタイプについては、今後の章で説明します。
整数型
次の表は、標準の整数型とそのストレージサイズと値の範囲の詳細を示しています-
Type | Storage size | Value range |
---|---|---|
char | 1 byte | -128 to 127 or 0 to 255 |
unsigned char | 1 byte | 0 to 255 |
signed char | 1 byte | -128 to 127 |
int | 2 or 4 bytes | -32,768 to 32,767 or -2,147,483,648 to 2,147,483,647 |
unsigned int | 2 or 4 bytes | 0 to 65,535 or 0 to 4,294,967,295 |
short | 2 bytes | -32,768 to 32,767 |
unsigned short | 2 bytes | 0 to 65,535 |
long | 8 bytes | -9223372036854775808 to 9223372036854775807 |
unsigned long | 8 bytes | 0 to 18446744073709551615 |
特定のプラットフォームで型または変数の正確なサイズを取得するには、 sizeof 演算子を使用できます。 式_sizeof(type)_は、オブジェクトまたはタイプのストレージサイズをバイト単位で生成します。 以下に示すのは、limits.hヘッダーファイルで定義されているさまざまな定数を使用して、マシン上のさまざまなタイプのサイズを取得する例です-
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <float.h>
int main(int argc, char** argv) {
printf("CHAR_BIT : %d\n", CHAR_BIT);
printf("CHAR_MAX : %d\n", CHAR_MAX);
printf("CHAR_MIN : %d\n", CHAR_MIN);
printf("INT_MAX : %d\n", INT_MAX);
printf("INT_MIN : %d\n", INT_MIN);
printf("LONG_MAX : %ld\n", (long) LONG_MAX);
printf("LONG_MIN : %ld\n", (long) LONG_MIN);
printf("SCHAR_MAX : %d\n", SCHAR_MAX);
printf("SCHAR_MIN : %d\n", SCHAR_MIN);
printf("SHRT_MAX : %d\n", SHRT_MAX);
printf("SHRT_MIN : %d\n", SHRT_MIN);
printf("UCHAR_MAX : %d\n", UCHAR_MAX);
printf("UINT_MAX : %u\n", (unsigned int) UINT_MAX);
printf("ULONG_MAX : %lu\n", (unsigned long) ULONG_MAX);
printf("USHRT_MAX : %d\n", (unsigned short) USHRT_MAX);
return 0;
}
上記のプログラムをコンパイルして実行すると、Linuxで次の結果が生成されます-
CHAR_BIT : 8
CHAR_MAX : 127
CHAR_MIN : -128
INT_MAX : 2147483647
INT_MIN : -2147483648
LONG_MAX : 9223372036854775807
LONG_MIN : -9223372036854775808
SCHAR_MAX : 127
SCHAR_MIN : -128
SHRT_MAX : 32767
SHRT_MIN : -32768
UCHAR_MAX : 255
UINT_MAX : 4294967295
ULONG_MAX : 18446744073709551615
USHRT_MAX : 65535
浮動小数点型
次の表は、ストレージのサイズと値の範囲、およびその精度を備えた標準の浮動小数点型の詳細を示しています-
Type | Storage size | Value range | Precision |
---|---|---|---|
float | 4 byte | 1.2E-38 to 3.4E+38 | 6 decimal places |
double | 8 byte | 2.3E-308 to 1.7E+308 | 15 decimal places |
long double | 10 byte | 3.4E-4932 to 1.1E+4932 | 19 decimal places |
ヘッダーファイルfloat.hは、これらの値およびプログラムで実数のバイナリ表現に関するその他の詳細を使用できるマクロを定義します。 次の例は、フロート型とその範囲値によって取得されたストレージスペースを印刷します-
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <float.h>
int main(int argc, char* *argv) {
printf("Storage size for float : %d \n", sizeof(float));
printf("FLT_MAX : %g\n", (float) FLT_MAX);
printf("FLT_MIN : %g\n", (float) FLT_MIN);
printf("-FLT_MAX : %g\n", (float) -FLT_MAX);
printf("-FLT_MIN : %g\n", (float) -FLT_MIN);
printf("DBL_MAX : %g\n", (double) DBL_MAX);
printf("DBL_MIN : %g\n", (double) DBL_MIN);
printf("-DBL_MAX : %g\n", (double) -DBL_MAX);
printf("Precision value: %d\n", FLT_DIG );
return 0;
}
上記のプログラムをコンパイルして実行すると、Linuxで次の結果が生成されます-
Storage size for float : 4
FLT_MAX : 3.40282e+38
FLT_MIN : 1.17549e-38
-FLT_MAX : -3.40282e+38
-FLT_MIN : -1.17549e-38
DBL_MAX : 1.79769e+308
DBL_MIN : 2.22507e-308
-DBL_MAX : -1.79769e+308
Precision value: 6
ボイドタイプ
voidタイプは、使用可能な値がないことを指定します。 それは3種類の状況で使用されます-
Sr.No. | Types & Description |
---|---|
1 |
Cには値を返さないさまざまな関数がありますが、これらの関数はvoidを返します。 戻り値のない関数の戻り値の型はvoidです。 たとえば、 void exit(int status); |
2 |
Function arguments as void Cには、パラメーターを受け入れないさまざまな関数があります。 パラメータを持たない関数はvoidを受け入れることができます。 たとえば、 int rand(void); |
3 |
Pointers to void void 型のポインターはオブジェクトのアドレスを表しますが、その型は表しません。 たとえば、メモリ割り当て関数 *void malloc(size_t size); *は、任意のデータ型にキャストできるvoidへのポインタを返します。 |
C-変数
変数は、プログラムが操作できるストレージ領域に付けられた名前に他なりません。 Cの各変数には特定の型があり、変数のメモリのサイズとレイアウトを決定します。そのメモリ内に保存できる値の範囲。変数に適用できる一連の操作。
変数の名前は、文字、数字、およびアンダースコア文字で構成できます。 文字またはアンダースコアで始まる必要があります。 Cでは大文字と小文字が区別されるため、大文字と小文字は区別されます。 前の章で説明した基本タイプに基づいて、次の基本変数タイプがあります-
Sr.No. | Type & Description |
---|---|
1 |
char 通常、単一のオクテット(1バイト)。 これは整数型です。 |
2 |
int マシンの整数の最も自然なサイズ。 |
3 |
float 単精度浮動小数点値。 |
4 |
double 倍精度の浮動小数点値。 |
5 |
void タイプがないことを表します。 |
Cプログラミング言語では、他のさまざまなタイプの変数を定義することもできます。これについては、列挙、ポインター、配列、構造、ユニオンなどの後続の章で説明します。 この章では、基本的な変数タイプのみを学習します。
Cの変数定義
変数定義は、変数用に作成するストレージの場所と量をコンパイラーに指示します。 変数の定義は、データ型を指定し、次のようにその型の1つ以上の変数のリストが含まれています-
type variable_list;
ここで、 type は、char、w_char、int、float、double、bool、またはユーザー定義オブジェクトを含む有効なCデータ型でなければなりません。 variable_list は、コンマで区切られた1つ以上の識別子名で構成されます。 いくつかの有効な宣言がここに示されています-
int i, j, k;
char c, ch;
float f, salary;
double d;
行 int i、j、k; は、変数i、j、およびkを宣言および定義します。 int型のi、j、kという名前の変数を作成するようコンパイラーに指示します。
変数は、宣言で初期化(初期値を割り当て)できます。 初期化子は、等号とそれに続く定数式で構成されます-
type variable_name = value;
いくつかの例は-
extern int d = 3, f = 5; //declaration of d and f.
int d = 3, f = 5; //definition and initializing d and f.
byte z = 22; //definition and initializes z.
char x = 'x'; //the variable x has the value 'x'.
初期化子のない定義の場合:静的ストレージ期間を持つ変数は、暗黙的にNULLで初期化されます(すべてのバイトの値は0です)。他のすべての変数の初期値は未定義です。
Cの変数宣言
変数宣言は、指定されたタイプと名前の変数が存在することをコンパイラーに保証します。これにより、コンパイラーは、変数に関する完全な詳細を必要とせずに、さらにコンパイルを進めることができます。 変数定義はコンパイル時のみ意味を持ち、コンパイラはプログラムをリンクするときに実際の変数定義を必要とします。
変数宣言は、複数のファイルを使用していて、プログラムのリンク時に使用できるファイルの1つで変数を定義するときに役立ちます。 キーワード extern を使用して、任意の場所で変数を宣言します。 Cプログラムでは変数を複数回宣言できますが、ファイル、関数、またはコードブロックで定義できるのは1回だけです。
例
次の例を試してください。変数は上部で宣言されていますが、メイン関数内で定義および初期化されています-
#include <stdio.h>
//Variable declaration:
extern int a, b;
extern int c;
extern float f;
int main () {
/*variable definition:*/
int a, b;
int c;
float f;
/*actual initialization*/
a = 10;
b = 20;
c = a + b;
printf("value of c : %d \n", c);
f = 70.0/3.0;
printf("value of f : %f \n", f);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
value of c : 30
value of f : 23.333334
同じ概念が関数宣言にも当てはまり、宣言時に関数名を指定し、実際の定義は他のどこでも指定できます。 たとえば-
//function declaration
int func();
int main() {
//function call
int i = func();
}
//function definition
int func() {
return 0;
}
Cの左辺値と右辺値
Cには2種類の式があります-
- lvalue -メモリ位置を参照する式は「lvalue」式と呼ばれます。 左辺値は、割り当ての左辺または右辺として表示される場合があります。
- rvalue -rvalueという用語は、メモリ内のあるアドレスに格納されているデータ値を指します。 右辺値は、値を割り当てることができない式です。つまり、右辺には右辺が表示されますが、左辺には表示されない場合があります。
変数は左辺値であるため、割り当ての左側に表示される場合があります。 数値リテラルは右辺値であるため、割り当てられず、左側に表示できません。 次の有効および無効なステートメントを見てください-
int g = 20;//valid statement
10 = 20;//invalid statement; would generate compile-time error
C-定数とリテラル
定数は、プログラムの実行中に変更されない可能性がある固定値を指します。 これらの固定値は*リテラル*とも呼ばれます。
定数は、_整数定数、浮動定数、文字定数、または文字列リテラル_などの基本データ型のいずれかです。 列挙定数もあります。
定数は、定義後に値を変更できないことを除いて、通常の変数と同様に扱われます。
整数リテラル
整数リテラルは、10進、8進、または16進定数です。 プレフィックスは、基数または基数を指定します。16進数の場合は0xまたは0X、8進数の場合は0、10進数の場合は何もありません。
整数リテラルには、UとLを組み合わせたサフィックスを付けることもできます。それぞれ、符号なしとロングを表します。 接尾辞は大文字でも小文字でも、任意の順序で指定できます。
ここに整数リテラルのいくつかの例があります-
212 /*Legal*/
215u /*Legal*/
0xFeeL /*Legal*/
078 /*Illegal: 8 is not an octal digit*/
032UU /*Illegal: cannot repeat a suffix*/
以下は、整数リテラルのさまざまなタイプの他の例です-
85 /*decimal*/
0213 /*octal*/
0x4b /*hexadecimal*/
30 /*int*/
30u /*unsigned int*/
30l /*long*/
30ul /*unsigned long*/
浮動小数点リテラル
浮動小数点リテラルには、整数部、小数点、小数部、指数部があります。 浮動小数点リテラルは、10進数形式または指数形式で表現できます。
小数形式を表す際には、小数点、指数、またはその両方を含める必要があります。そして、指数形式を表す間、整数部、小数部、またはその両方を含める必要があります。 符号付き指数は、eまたはEによって導入されます。
浮動小数点リテラルの例をいくつか示します-
3.14159 /*Legal*/
314159E-5L /*Legal*/
510E /*Illegal: incomplete exponent*/
210f /*Illegal: no decimal or exponent*/
.e55 /*Illegal: missing integer or fraction*/
文字定数
文字リテラルは一重引用符で囲まれています。たとえば、「x」は char 型の単純な変数に格納できます。
文字リテラルは、プレーン文字(例: 'x')、エスケープシーケンス(例: '\ t')、またはユニバーサル文字(例: '\ u02C0')です。
Cには、改行(\ n)やタブ(\ t)など、バックスラッシュが前に付いたときに特別な意味を表す特定の文字があります。
- link:#[ここに、このようなエスケープシーケンスコードのリストがあります-]
以下は、いくつかのエスケープシーケンス文字を示す例です-
#include <stdio.h>
int main() {
printf("Hello\tWorld\n\n");
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Hello World
文字列リテラル
文字列リテラルまたは定数は、二重引用符 ""で囲まれています。 文字列には、文字リテラルに類似した文字が含まれます:プレーン文字、エスケープシーケンス、およびユニバーサル文字。
文字列リテラルを使用して長い行を複数の行に分割し、それらを空白で区切ります。
文字列リテラルの例を次に示します。 3つの形式はすべて同じ文字列です。
"hello, dear"
"hello, \
dear"
"hello, " "d" "ear"
定数の定義
Cには定数を定義する2つの簡単な方法があります-
- *#define *プリプロセッサを使用します。
- const キーワードを使用します。
#defineプリプロセッサ
以下に示すのは、#defineプリプロセッサを使用して定数を定義する形式です-
#define identifier value
次の例では、詳細に説明します-
#include <stdio.h>
#define LENGTH 10
#define WIDTH 5
#define NEWLINE '\n'
int main() {
int area;
area = LENGTH * WIDTH;
printf("value of area : %d", area);
printf("%c", NEWLINE);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
value of area : 50
constキーワード
次のように、 const プレフィックスを使用して、特定のタイプの定数を宣言できます-
const type variable = value;
次の例では、詳細に説明します-
#include <stdio.h>
int main() {
const int LENGTH = 10;
const int WIDTH = 5;
const char NEWLINE = '\n';
int area;
area = LENGTH * WIDTH;
printf("value of area : %d", area);
printf("%c", NEWLINE);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
value of area : 50
CAPITALSで定数を定義することは、優れたプログラミング手法であることに注意してください。
C-ストレージクラス
ストレージクラスは、Cプログラム内の変数や関数の有効範囲(可視性)と寿命を定義します。 変更するタイプに先行します。 Cプログラムには4つの異なるストレージクラスがあります-
- auto
- 登録
- 静的
- 外面
自動ストレージクラス
*auto* ストレージクラスは、すべてのローカル変数のデフォルトストレージクラスです。
{
int mount;
auto int month;
}
上記の例では、同じストレージクラスで2つの変数を定義しています。 「auto」は、関数、つまりローカル変数内でのみ使用できます。
レジスタストレージクラス
*register* ストレージクラスは、RAMではなくレジスタに保存するローカル変数を定義するために使用されます。 これは、変数の最大サイズがレジスタサイズ(通常は1ワード)に等しく、単項 '&'演算子を適用できないことを意味します(メモリ位置がないため)。
{
register int miles;
}
レジスタは、カウンタなどの迅速なアクセスを必要とする変数にのみ使用する必要があります。 また、「レジスタ」を定義しても、変数がレジスタに格納されるわけではないことに注意してください。 これは、ハードウェアと実装の制限に応じて、レジスタに格納される可能性があることを意味します。
静的ストレージクラス
*static* ストレージクラスは、プログラムの有効期間中にローカル変数を作成および破棄するのではなく、スコープに出入りするたびにローカル変数を保持するようコンパイラーに指示します。 したがって、ローカル変数を静的にすると、関数呼び出し間で値を維持できます。
static修飾子は、グローバル変数にも適用できます。 これが行われると、その変数のスコープは、それが宣言されているファイルに制限されます。
Cプログラミングでは、 static がグローバル変数で使用されると、そのメンバーの1つのコピーのみがそのクラスのすべてのオブジェクトで共有されます。
#include <stdio.h>
/*function declaration*/
void func(void);
static int count = 5;/*global variable*/
main() {
while(count--) {
func();
}
return 0;
}
/*function definition*/
void func( void ) {
static int i = 5;/*local static variable*/
i++;
printf("i is %d and count is %d\n", i, count);
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
i is 6 and count is 4
i is 7 and count is 3
i is 8 and count is 2
i is 9 and count is 1
i is 10 and count is 0
外部ストレージクラス
*extern* ストレージクラスは、すべてのプログラムファイルに表示されるグローバル変数の参照を提供するために使用されます。 'extern'を使用する場合、変数は初期化できませんが、以前に定義された保存場所で変数名を指します。
複数のファイルがあり、他のファイルでも使用されるグローバル変数または関数を定義すると、別のファイルで_extern_が使用され、定義された変数または関数の参照が提供されます。 理解のためだけに、_extern_は別のファイルでグローバル変数または関数を宣言するために使用されます。
extern修飾子は、以下で説明するように、同じグローバル変数または関数を共有する2つ以上のファイルがある場合に最も一般的に使用されます。
- 最初のファイル:main.c *
#include <stdio.h>
int count ;
extern void write_extern();
main() {
count = 5;
write_extern();
}
*2番目のファイル:support.c*
#include <stdio.h>
extern int count;
void write_extern(void) {
printf("count is %d\n", count);
}
ここで、_extern_は、2番目のファイルで_count_を宣言するために使用されています。最初のファイルmain.cで定義されているためです。 今、次のようにこれらの2つのファイルをコンパイルします-
$gcc main.c support.c
実行可能プログラム a.out が生成されます。 このプログラムが実行されると、次の結果が生成されます-
count is 5
C-演算子
演算子は、特定の数学関数または論理関数を実行するようコンパイラーに指示する記号です。 C言語は組み込みの演算子が豊富であり、次の種類の演算子を提供します-
- 算術演算子
- 関係演算子
- 論理演算子
- ビット演算子
- 割り当て演算子
- その他の演算子
この章では、各演算子の動作方法について説明します。
算術演算子
次の表は、C言語でサポートされているすべての算術演算子を示しています。 変数 A が10を保持し、変数 B が20を保持すると仮定します-
リンク:/cprogramming/c_arithmetic_operators [例を表示]
Operator | Description | Example |
---|---|---|
PLUS | Adds two operands. | A PLUS B = 30 |
− | Subtracts second operand from the first. | A − B = -10 |
* | Multiplies both operands. | A* B = 200 |
/ | Divides numerator by de-numerator. | B/A = 2 |
% | Modulus Operator and remainder of after an integer division. | B % A = 0 |
++ | Increment operator increases the integer value by one. | A++ = 11 |
— | Decrement operator decreases the integer value by one. | A-- = 9 |
関係演算子
次の表は、Cでサポートされているすべての関係演算子を示しています。 変数 A が10を保持し、変数 B が20を保持すると仮定します-
リンク:/cprogramming/c_relational_operators [例を表示]
Operator | Description | Example |
---|---|---|
== | Checks if the values of two operands are equal or not. If yes, then the condition becomes true. | (A == B) is not true. |
!= | Checks if the values of two operands are equal or not. If the values are not equal, then the condition becomes true. | (A != B) is true. |
> | Checks if the value of left operand is greater than the value of right operand. If yes, then the condition becomes true. | (A > B) is not true. |
< | Checks if the value of left operand is less than the value of right operand. If yes, then the condition becomes true. | (A < B) is true. |
>= | Checks if the value of left operand is greater than or equal to the value of right operand. If yes, then the condition becomes true. | (A >= B) is not true. |
⇐ | Checks if the value of left operand is less than or equal to the value of right operand. If yes, then the condition becomes true. | (A ⇐ B) is true. |
論理演算子
次の表は、C言語でサポートされているすべての論理演算子を示しています。 変数 A が1を保持し、変数 B が0を保持すると仮定します-
リンク:/cprogramming/c_logical_operators [例を表示]
Operator | Description | Example |
---|---|---|
&& | Called Logical AND operator. If both the operands are non-zero, then the condition becomes true. | (A && B) is false. |
Called Logical OR Operator. If any of the two operands is non-zero, then the condition becomes true. | (A | |
B) is true. | ! | Called Logical NOT Operator. It is used to reverse the logical state of its operand. If a condition is true, then Logical NOT operator will make it false. |
ビット演算子
ビット演算子はビットに対して機能し、ビットごとの操作を実行します。 &、|、および^の真理値表は次のとおりです-
p | q | p & q | p | q |
---|---|---|---|---|
p ^ q | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 1 |
1 | 1 | 1 | 1 | 1 |
0 | 1 | 0 | 0 | 1 |
バイナリ形式でA = 60とB = 13と仮定すると、それらは次のようになります-
A = 0011 1100
B = 0000 1101
A&B = 0000 1100
A | B = 0011 1101
A ^ B = 0011 0001
〜A = 1100 0011
次の表に、Cでサポートされているビットごとの演算子を示します。 変数「A」が60を保持し、変数「B」が13を保持すると仮定します-
リンク:/cprogramming/c_bitwise_operators [例を表示]
[cols=",,",options="header",]
|===
|Operator |Description |Example |& |Binary AND Operator copies a bit to the result if it exists in both operands. |(A & B) = 12, i.e., 0000 1100 || |Binary OR Operator copies a bit if it exists in either operand. |(A | B) = 61, i.e., 0011 1101 |^ |Binary XOR Operator copies the bit if it is set in one operand but not both. |(A ^ B) = 49, i.e., 0011 0001 |~ |Binary One's Complement Operator is unary and has the effect of 'flipping' bits. |(~A ) = ~(60), i.e,. -0111101 |<< |Binary Left Shift Operator. The left operands value is moved left by the number of bits specified by the right operand. |A << 2 = 240 i.e., 1111 0000 |>> |Binary Right Shift Operator. The left operands value is moved right by the number of bits specified by the right operand. |A >> 2 = 15 i.e., 0000 1111
|===
=== 割り当て演算子
次の表は、C言語でサポートされている割り当て演算子を示しています-
リンク:/cprogramming/c_assignment_operators [例を表示]
[cols=",,",options="header",]
|===
|Operator |Description |Example |= |Simple assignment operator. Assigns values from right side operands to left side operand |C = A + B will assign the value of A + B to C |+= |Add AND assignment operator. It adds the right operand to the left operand and assign the result to the left operand. |C += A is equivalent to C = C + A |-= |Subtract AND assignment operator. It subtracts the right operand from the left operand and assigns the result to the left operand. |C -= A is equivalent to C = C - A |*= |Multiply AND assignment operator. It multiplies the right operand with the left operand and assigns the result to the left operand. |C *= A is equivalent to C = C * A |/= |Divide AND assignment operator. It divides the left operand with the right operand and assigns the result to the left operand. |C/= A is equivalent to C = C/A |%= |Modulus AND assignment operator. It takes modulus using two operands and assigns the result to the left operand. |C %= A is equivalent to C = C % A |<<= |Left shift AND assignment operator. |C <<= 2 is same as C = C << 2 |>>= |Right shift AND assignment operator. |C >>= 2 is same as C = C >> 2 |&= |Bitwise AND assignment operator. |C &= 2 is same as C = C & 2 |^= |Bitwise exclusive OR and assignment operator. |C ^= 2 is same as C = C ^ 2 ||= |Bitwise inclusive OR and assignment operator. |C |= 2 is same as C = C | 2
|===
=== その他の演算子&map; sizeof&ternary
上記で説明した演算子の他に、 *sizeof* や*?を含む他の重要な演算子がいくつかあります。 :* C言語でサポートされています。
リンク:/cprogramming/c_sizeof_operator [例を表示]
[cols=",,",options="header",]
|===
|Operator |Description |Example |sizeof() |Returns the size of a variable. |sizeof(a), where a is integer, will return 4. |& |Returns the address of a variable. |&a; returns the actual address of the variable. |* |Pointer to a variable. |*a; |? : |Conditional Expression. |If Condition is true ? then value X : otherwise value Y
|===
=== Cでの演算子の優先順位
演算子の優先順位は、式内の用語のグループ化を決定し、式の評価方法を決定します。 特定の演算子は、他の演算子よりも優先順位が高くなっています。たとえば、乗算演算子は加算演算子よりも優先順位が高くなります。
たとえば、x = 7 + 3 * 2;ここでは、演算子*の優先順位が+より高いため、xには20ではなく13が割り当てられます。したがって、最初に3 * 2で乗算され、次に7に加算されます。
ここでは、優先順位が最も高い演算子が表の上部に表示され、優先順位が最も低い演算子が下部に表示されます。 式内では、優先順位の高い演算子が最初に評価されます。
リンク:/cprogramming/c_operators_precedence [例を表示]
[cols=",,",options="header",]
|===
|Category |Operator |Associativity |Postfix |() [] -> . ++ - - |Left to right |Unary |+ - ! ~ ++ - - (type)* & sizeof |Right to left |Multiplicative | */% |Left to right |Additive |+ - |Left to right |Shift |<< >> |Left to right |Relational |< <= > >= |Left to right |Equality |== != |Left to right |Bitwise AND |& |Left to right |Bitwise XOR |^ |Left to right |Bitwise OR || |Left to right |Logical AND |&& |Left to right |Logical OR ||| |Left to right |Conditional |?: |Right to left |Assignment |= += -=* =/= %=>>= <<= &= ^= |= |Right to left |Comma |, |Left to right
|===
C-意思決定
意思決定構造では、プログラマーが、プログラムによって評価またはテストされる1つ以上の条件、および条件が真であると判断された場合に実行されるステートメント、およびオプションで条件が実行された場合に実行される他のステートメントを指定する必要があります偽と判断されます。
以下に示すのは、ほとんどのプログラミング言語で見られる典型的な意思決定構造の一般的な形式です-
Cプログラミング言語は、すべての*非ゼロ*および*非ヌル*値を true と見なし、ゼロ*または *null の場合、 false 値と見なされます。
Cプログラミング言語は、次のタイプの意思決定ステートメントを提供します。
Sr.No. | Statement & Description |
---|---|
1 |
|
2 |
|
3 |
1つの if または else if ステートメントを別の if または else if ステートメント内で使用できます。 |
4 |
|
5 |
1つの switch ステートメントを別の switch ステートメント内で使用できます。 |
は? :オペレーター
条件演算子? :*前の章の *if … else ステートメントを置き換えるために使用できます。 それは次の一般的な形式を持っています-
Exp1 ? Exp2 : Exp3;
Exp1、Exp2、およびExp3は式です。 コロンの使用と配置に注意してください。
aの値 式はこのように決定されます-
- Exp1が評価されます。 真の場合、Exp2が評価され、?全体の値になります。 式です。
- Exp1がfalseの場合、Exp3が評価され、その値が式の値になります。
C-ループ
コードのブロックを複数回実行する必要がある場合、状況が発生する可能性があります。 一般に、ステートメントは順番に実行されます。関数の最初のステートメントが最初に実行され、次に2番目のステートメントが実行されます。
プログラミング言語は、より複雑な実行パスを可能にするさまざまな制御構造を提供します。
ループステートメントを使用すると、ステートメントまたはステートメントのグループを複数回実行できます。 以下に示すのは、ほとんどのプログラミング言語での一般的なループ文の形式です-
Cプログラミング言語は、ループ要件を処理するために次のタイプのループを提供します。
Sr.No. | Loop Type & Description |
---|---|
1 |
特定の条件が真の間、ステートメントまたはステートメントのグループを繰り返します。 ループ本体を実行する前に条件をテストします。 |
2 |
一連のステートメントを複数回実行し、ループ変数を管理するコードを短縮します。 |
3 |
ループ本体の最後で条件をテストすることを除いて、while文に似ています。 |
4 |
while、for、またはdo..whileループ内で1つ以上のループを使用できます。 |
ループ制御ステートメント
ループ制御ステートメントは、通常のシーケンスから実行を変更します。 実行がスコープを離れると、そのスコープで作成されたすべての自動オブジェクトが破棄されます。
Cは、次の制御ステートメントをサポートしています。
Sr.No. | Control Statement & Description |
---|---|
1 |
|
2 |
ループがその本体の残りをスキップし、反復する前にその状態をすぐに再テストします。 |
3 |
ラベル付きステートメントに制御を移します。 |
無限ループ
条件が決して偽にならない場合、ループは無限ループになります。 for ループは伝統的にこの目的に使用されます。 「for」ループを形成する3つの式はいずれも必要ないため、条件式を空のままにして無限ループを作成できます。
#include <stdio.h>
int main () {
for( ; ; ) {
printf("This loop will run forever.\n");
}
return 0;
}
条件式が存在しない場合、trueと見なされます。 初期化および増分式を使用できますが、Cプログラマーはより一般的にfor(;;)コンストラクトを使用して無限ループを示します。
注-Ctrl + Cキーを押すと、無限ループを終了できます。
C-関数
関数は、一緒にタスクを実行するステートメントのグループです。 すべてのCプログラムには少なくとも1つの関数(* main()*)があり、最も単純なプログラムはすべて追加の関数を定義できます。
コードを別々の機能に分割できます。 コードを異なる関数に分割する方法はユーザー次第ですが、論理的には、各関数が特定のタスクを実行するように分割されます。
関数*宣言*は、関数の名前、戻り値の型、およびパラメーターについてコンパイラーに通知します。 関数 definition は、関数の実際の本体を提供します。
C標準ライブラリは、プログラムが呼び出すことができる多数の組み込み関数を提供します。 たとえば、2つの文字列を連結する* strcat()、1つのメモリ位置を別の位置にコピーする memcpy()*、およびその他の多くの関数。
関数は、メソッド、サブルーチン、またはプロシージャなどとも呼ばれます。
関数を定義する
Cプログラミング言語の関数定義の一般的な形式は次のとおりです-
return_type function_name( parameter list ) {
body of the function
}
Cプログラミングの関数定義は、_function header_と_function body_で構成されています。 ここに関数のすべての部分があります-
- 戻り値の型-関数は値を返す場合があります。 return_type は、関数が返す値のデータ型です。 一部の関数は、値を返さずに目的の操作を実行します。 この場合、return_typeはキーワード void です。
- 関数名-これは関数の実際の名前です。 関数名とパラメーターリストは一緒に関数シグネチャを構成します。
- パラメータ-パラメータはプレースホルダのようなものです。 関数が呼び出されると、パラメーターに値を渡します。 この値は、実パラメーターまたは引数と呼ばれます。 パラメーターリストは、関数のパラメーターのタイプ、順序、および数を参照します。 パラメーターはオプションです。つまり、関数にパラメーターを含めることはできません。
- 関数本体-関数本体には、関数の動作を定義するステートメントのコレクションが含まれています。
例
以下に、* max()*という関数のソースコードを示します。 この関数は、num1とnum2の2つのパラメータを取り、2つの間の最大値を返します-
/*function returning the max between two numbers*/
int max(int num1, int num2) {
/*local variable declaration*/
int result;
if (num1 > num2)
result = num1;
else
result = num2;
return result;
}
関数宣言
関数*宣言*は、関数名と関数の呼び出し方法をコンパイラーに伝えます。 関数の実際の本体は個別に定義できます。
関数宣言には次の部分があります-
return_type function_name( parameter list );
上記の定義された関数max()の場合、関数宣言は次のとおりです-
int max(int num1, int num2);
パラメータ名は、それらの型が必要な関数宣言では重要ではないので、次も有効な宣言です-
int max(int, int);
あるソースファイルで関数を定義し、別のファイルでその関数を呼び出す場合、関数宣言が必要です。 そのような場合、関数を呼び出すファイルの先頭で関数を宣言する必要があります。
関数を呼び出す
C関数を作成するときに、関数が何をする必要があるかを定義します。 関数を使用するには、その関数を呼び出して定義済みのタスクを実行する必要があります。
プログラムが関数を呼び出すと、プログラム制御は呼び出された関数に転送されます。 呼び出された関数は定義されたタスクを実行し、returnステートメントが実行されるか、関数終了の閉じ中括弧に到達すると、プログラム制御をメインプログラムに戻します。
関数を呼び出すには、必要なパラメーターと関数名を渡すだけで済みます。関数が値を返す場合、戻り値を保存できます。 たとえば-
#include <stdio.h>
/*function declaration*/
int max(int num1, int num2);
int main () {
/*local variable definition*/
int a = 100;
int b = 200;
int ret;
/*calling a function to get max value*/
ret = max(a, b);
printf( "Max value is : %d\n", ret );
return 0;
}
/*function returning the max between two numbers*/
int max(int num1, int num2) {
/*local variable declaration*/
int result;
if (num1 > num2)
result = num1;
else
result = num2;
return result;
}
main()とともにmax()を保持し、ソースコードをコンパイルしました。 最終的な実行可能ファイルを実行している間、それは次の結果を生成します-
Max value is : 200
関数の引数
関数が引数を使用する場合、引数の値を受け入れる変数を宣言する必要があります。 これらの変数は、関数の*仮パラメータ*と呼ばれます。
仮パラメータは、関数内の他のローカル変数のように動作し、関数に入ると作成され、終了すると破棄されます。
関数を呼び出している間、引数を関数に渡すことができる2つの方法があります-
Sr.No. | Call Type & Description |
---|---|
1 |
このメソッドは、引数の実際の値を関数の仮パラメーターにコピーします。 この場合、関数内のパラメーターを変更しても、引数には影響しません。 |
2 |
このメソッドは、引数のアドレスを仮パラメーターにコピーします。 関数内では、呼び出しで使用される実際の引数にアクセスするためにアドレスが使用されます。 これは、パラメーターに加えられた変更が引数に影響することを意味します。 |
デフォルトでは、Cは call by value を使用して引数を渡します。 一般に、関数内のコードは、関数の呼び出しに使用される引数を変更できないことを意味します。
C-スコープルール
プログラミングのスコープとは、定義された変数が存在し、その変数を超えてアクセスできないプログラムの領域です。 Cプログラミング言語で変数を宣言できる場所は3つあります-
local 変数と呼ばれる関数またはブロック内。
global 変数と呼ばれるすべての関数の外側。
formal パラメータと呼ばれる関数パラメータの定義。
*local* および *global* 変数、および *formal* パラメーターについて理解しましょう。
ローカル変数
関数またはブロック内で宣言される変数は、ローカル変数と呼ばれます。 それらは、その関数またはコードブロック内にあるステートメントでのみ使用できます。 ローカル変数は、自身の外部の関数には認識されません。 次の例は、ローカル変数の使用方法を示しています。 ここで、変数a、b、およびcはすべてmain()関数に対してローカルです。
#include <stdio.h>
int main () {
/*local variable declaration*/
int a, b;
int c;
/*actual initialization*/
a = 10;
b = 20;
c = a + b;
printf ("value of a = %d, b = %d and c = %d\n", a, b, c);
return 0;
}
グローバル変数
グローバル変数は、関数の外側、通常はプログラムの上部で定義されます。 グローバル変数は、プログラムの存続期間を通じてその値を保持し、プログラムに定義された関数のいずれかからアクセスできます。
グローバル変数には、どの関数からもアクセスできます。 つまり、グローバル変数は、宣言後、プログラム全体で使用できます。 次のプログラムは、プログラムでグローバル変数がどのように使用されるかを示しています。
#include <stdio.h>
/*global variable declaration*/
int g;
int main () {
/*local variable declaration*/
int a, b;
/*actual initialization*/
a = 10;
b = 20;
g = a + b;
printf ("value of a = %d, b = %d and g = %d\n", a, b, g);
return 0;
}
プログラムはローカル変数とグローバル変数に同じ名前を付けることができますが、関数内のローカル変数の値が優先されます。 ここに例があります-
#include <stdio.h>
/*global variable declaration*/
int g = 20;
int main () {
/*local variable declaration*/
int g = 10;
printf ("value of g = %d\n", g);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
value of g = 10
正式なパラメーター
仮パラメータは、関数内のローカル変数として扱われ、グローバル変数よりも優先されます。 以下は例です-
#include <stdio.h>
/*global variable declaration*/
int a = 20;
int main () {
/*local variable declaration in main function*/
int a = 10;
int b = 20;
int c = 0;
printf ("value of a in main() = %d\n", a);
c = sum( a, b);
printf ("value of c in main() = %d\n", c);
return 0;
}
/*function to add two integers*/
int sum(int a, int b) {
printf ("value of a in sum() = %d\n", a);
printf ("value of b in sum() = %d\n", b);
return a + b;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
value of a in main() = 10
value of a in sum() = 10
value of b in sum() = 20
value of c in main() = 30
ローカル変数とグローバル変数の初期化
ローカル変数が定義されると、システムによって初期化されません。自分で初期化する必要があります。 グローバル変数は、次のように定義すると、システムによって自動的に初期化されます-
Data Type | Initial Default Value |
---|---|
int | 0 |
char | '\0' |
float | 0 |
double | 0 |
pointer | NULL |
変数を適切に初期化することをお勧めします。そうしないと、初期化されていない変数がメモリ位置で既に利用可能なゴミ値を取得するため、プログラムが予期しない結果を生成する可能性があります。
C-配列
同じタイプの要素の固定サイズの順次コレクションを格納できる一種のデータ構造を配列します。 配列はデータのコレクションを格納するために使用されますが、配列を同じタイプの変数のコレクションと考える方が便利な場合がよくあります。
number0、number1、…、number99などの個々の変数を宣言する代わりに、numbersなどの1つの配列変数を宣言し、numbers [0]、numbers [1]、…、numbers [99]を使用して表現します個々の変数。 配列内の特定の要素は、インデックスによってアクセスされます。
すべての配列は、連続したメモリ位置で構成されています。 最下位アドレスは最初の要素に対応し、最上位アドレスは最後の要素に対応します。
配列の宣言
Cで配列を宣言するために、プログラマは次のように配列に必要な要素の型と要素の数を指定します-
type arrayName [ arraySize ];
これは「単一次元配列」と呼ばれます。 arraySize はゼロより大きい整数定数でなければならず、 type は任意の有効なCデータ型にすることができます。 たとえば、double型の balance という10要素の配列を宣言するには、このステートメントを使用します-
double balance[10];
ここで、_balance_は、最大10個のdouble番号を保持するのに十分な変数配列です。
配列の初期化
あなたはCの配列を1つずつ、または次のように単一のステートメントを使用して初期化することができます-
double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};
中括弧\ {}の間の値の数は、角括弧[]の間の配列に対して宣言する要素の数より大きくすることはできません。
配列のサイズを省略すると、初期化を保持するのに十分な大きさの配列が作成されます。 したがって、あなたが書く場合-
double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};
前の例で作成したのとまったく同じ配列を作成します。 以下は、配列の単一の要素を割り当てるための例です-
balance[4] = 50.0;
上記のステートメントは、配列の5 ^ th ^要素に50.0の値を割り当てます。 すべての配列は、ベースインデックスとも呼ばれる最初の要素のインデックスとして0を持ち、配列の最後のインデックスは、配列の合計サイズから1を引いたものになります。 以下に示すのは、上で説明した配列の図的表現です-
配列要素へのアクセス
配列名にインデックスを付けることにより、要素にアクセスします。 これは、配列の名前の後に角かっこ内に要素のインデックスを配置することによって行われます。 たとえば-
double salary = balance[9];
上記のステートメントは、配列から10 ^ th ^要素を取得し、その値を給与変数に割り当てます。 次の例は、上記の3つの概念すべてを使用する方法を示しています。 宣言、割り当て、および配列へのアクセス-
#include <stdio.h>
int main () {
int n[ 10 ];/*n is an array of 10 integers*/
int i,j;
/*initialize elements of array n to 0*/
for ( i = 0; i < 10; i++ ) {
n[ i ] = i + 100;/*set element at location i to i + 100*/
}
/*output each array element's value*/
for (j = 0; j < 10; j++ ) {
printf("Element[%d] = %d\n", j, n[j] );
}
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109
配列の詳細
配列はCにとって重要であり、さらに注意が必要です。 配列に関連する次の重要な概念は、Cプログラマーには明らかなはずです-
Sr.No. | Concept & Description |
---|---|
1 |
Cは多次元配列をサポートしています。 多次元配列の最も単純な形式は、2次元配列です。 |
2 |
インデックスなしで配列の名前を指定することで、関数に配列へのポインタを渡すことができます。 |
3 |
Cでは、関数が配列を返すことができます。 |
4 |
インデックスなしで配列名を指定するだけで、配列の最初の要素へのポインタを生成できます。 |
C-ポインター
Cのポインターは簡単に学ぶことができます。 一部のCプログラミングタスクはポインターを使用してより簡単に実行でき、動的メモリ割り当てなどの他のタスクはポインターを使用しないと実行できません。 したがって、完璧なCプログラマーになるには、ポインターを学ぶ必要があります。 簡単で簡単な手順で学習を始めましょう。
ご存じのように、すべての変数はメモリロケーションであり、すべてのメモリロケーションには、メモリ内のアドレスを示すアンパサンド(&)演算子を使用してアクセスできるアドレスが定義されています。 定義された変数のアドレスを出力する次の例を考えてください-
#include <stdio.h>
int main () {
int var1;
char var2[10];
printf("Address of var1 variable: %x\n", &var1 );
printf("Address of var2 variable: %x\n", &var2 );
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Address of var1 variable: bff5a400
Address of var2 variable: bff5a3f6
ポインターとは何ですか?
- ポインタ*は、値が別の変数のアドレス、つまりメモリ位置の直接アドレスである変数です。 任意の変数または定数と同様に、ポインターを使用して変数アドレスを保存する前に、ポインターを宣言する必要があります。 ポインタ変数宣言の一般的な形式は-
type *var-name;
ここで、 type はポインターの基本型です。有効なCデータ型である必要があり、 var-name はポインター変数の名前です。 ポインターの宣言に使用されるアスタリスク*は、乗算に使用されるアスタリスクと同じです。 ただし、このステートメントでは、変数をポインターとして指定するためにアスタリスクが使用されています。 有効なポインタ宣言のいくつかを見てみましょう-
int *ip; /*pointer to an integer*/
double *dp; /*pointer to a double*/
float *fp; /*pointer to a float*/
char *ch /*pointer to a character*/
すべてのポインターの値の実際のデータ型は、整数、浮動小数点、文字、またはその他のいずれであっても同じで、メモリアドレスを表す長い16進数です。 異なるデータ型のポインターの唯一の違いは、ポインターが指す変数または定数のデータ型です。
ポインターの使用方法
いくつかの重要な操作がありますが、非常に頻繁にポインターを使用して行います。 (a)*ポインター変数を定義し、(b)変数のアドレスをポインターに割り当て、(c)が最終的にポインター変数で使用可能なアドレスの値にアクセスします。 これは、オペランドで指定されたアドレスにある変数の値を返す単項演算子**を使用して行われます。 次の例では、これらの操作を利用しています-
#include <stdio.h>
int main () {
int var = 20; /*actual variable declaration*/
int *ip; /*pointer variable declaration*/
ip = &var; /* store address of var in pointer variable*/
printf("Address of var variable: %x\n", &var );
/*address stored in pointer variable*/
printf("Address stored in ip variable: %x\n", ip );
/*access the value using the pointer*/
printf("Value of *ip variable: %d\n", *ip );
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Address of var variable: bffd8b3c
Address stored in ip variable: bffd8b3c
Value of *ip variable: 20
NULLポインター
割り当てられる正確なアドレスがない場合は、常にNULL値をポインター変数に割り当てることをお勧めします。 これは、変数宣言時に行われます。 NULLが割り当てられたポインターは、 null ポインターと呼ばれます。
NULLポインターは、いくつかの標準ライブラリで定義されている値がゼロの定数です。 次のプログラムを検討してください-
#include <stdio.h>
int main () {
int *ptr = NULL;
printf("The value of ptr is : %x\n", ptr );
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
The value of ptr is 0
ほとんどのオペレーティングシステムでは、アドレス0のメモリにアクセスすることは許可されていません。これは、メモリがオペレーティングシステムによって予約されているためです。 ただし、メモリアドレス0には特別な意味があります。ポインタがアクセス可能なメモリ位置を指すように意図されていないことを通知します。 ただし、慣例により、ポインターにNULL(ゼロ)値が含まれている場合、ポインターは何も指していないと見なされます。
ヌルポインタを確認するには、次のように「if」ステートメントを使用できます-
if(ptr) /*succeeds if p is not null*/
if(!ptr) /*succeeds if p is null*/
ポインターの詳細
ポインターには簡単ではあるが多くの概念があり、Cプログラミングにとって非常に重要です。 以下の重要なポインターの概念は、Cプログラマーには明らかなはずです-
Sr.No. | Concept & Description |
---|---|
1 |
ポインターで使用できる4つの算術演算子があります:+、-、、- |
2 |
配列を定義して、多数のポインターを保持できます。 |
3 |
Cでは、ポインターにポインターを置くことができます。 |
4 |
Passing pointers to functions in C 参照またはアドレスで引数を渡すと、呼び出された関数によって、呼び出された関数で渡された引数を変更できます。 |
5 |
Return pointer from functions in C Cでは、関数がローカル変数、静的変数、および動的に割り当てられたメモリへのポインターも返すことができます。 |
C-文字列
文字列は、実際には null 文字「\ 0」で終了する文字の1次元配列です。 したがって、nullで終わる文字列には、 null が後に続く文字列を構成する文字が含まれます。
次の宣言と初期化により、「Hello」という単語で構成される文字列が作成されます。 配列の末尾にヌル文字を保持するために、ストリングを含む文字配列のサイズは、「Hello」という単語の文字数よりも1つ多くなります。
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
あなたは配列の初期化のルールに従う場合は、次のように上記のステートメントを書くことができます-
char greeting[] = "Hello";
以下は、C/C ++で上記で定義された文字列のメモリ表示です-
実際には、文字列定数の最後に_null_文字を配置しません。 Cコンパイラは、配列を初期化するときに、文字列の末尾に「\ 0」を自動的に配置します。 上記の文字列を印刷してみましょう-
#include <stdio.h>
int main () {
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
printf("Greeting message: %s\n", greeting );
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Greeting message: Hello
Cはヌル終端文字列を操作する幅広い機能をサポートしています-
Sr.No. | Function & Purpose |
---|---|
1 |
strcpy(s1, s2); 文字列s2を文字列s1にコピーします。 |
2 |
strcat(s1, s2); 文字列s2を文字列s1の末尾に連結します。 |
3 |
strlen(s1); 文字列s1の長さを返します。 |
4 |
strcmp(s1, s2); s1とs2が同じ場合は0を返します。 s1 <s2の場合、0未満。 s1> s2の場合、0より大きい。 |
5 |
strchr(s1, ch); 文字列s1に最初に現れる文字chへのポインターを返します。 |
6 |
strstr(s1, s2); 文字列s1内で文字列s2が最初に現れる場所へのポインタを返します。 |
次の例では、上記の機能のいくつかを使用しています-
#include <stdio.h>
#include <string.h>
int main () {
char str1[12] = "Hello";
char str2[12] = "World";
char str3[12];
int len ;
/*copy str1 into str3*/
strcpy(str3, str1);
printf("strcpy( str3, str1) : %s\n", str3 );
/*concatenates str1 and str2*/
strcat( str1, str2);
printf("strcat( str1, str2): %s\n", str1 );
/*total lenghth of str1 after concatenation*/
len = strlen(str1);
printf("strlen(str1) : %d\n", len );
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
strcpy( str3, str1) : Hello
strcat( str1, str2): HelloWorld
strlen(str1) : 10
C-構造
配列を使用すると、同じ種類の複数のデータ項目を保持できる変数のタイプを定義できます。 同様に、 structure は、Cで使用可能な別のユーザー定義のデータ型であり、異なる種類のデータ項目を組み合わせることができます。
構造は、レコードを表すために使用されます。 図書館で本を追跡したいとします。 あなたは、各本に関する次の属性を追跡することができます-
- タイトル
- 著者
- 件名
- ブックID
構造の定義
構造を定義するには、 struct ステートメントを使用する必要があります。 structステートメントは、複数のメンバーを持つ新しいデータ型を定義します。 構造体ステートメントの形式は次のとおりです-
struct [structure tag] {
member definition;
member definition;
...
member definition;
} [one or more structure variables];
- 構造タグ*はオプションであり、各メンバー定義はint iなどの通常の変数定義です。またはfloat f;または他の有効な変数定義。 構造の定義の最後で、最後のセミコロンの前に、1つ以上の構造変数を指定できますが、これはオプションです。 ここにあなたが本の構造を宣言する方法があります-
struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
} book;
構造体メンバーへのアクセス
構造体のメンバーにアクセスするには、* memberアクセス演算子(。)を使用します。 メンバーアクセス演算子は、構造変数名とアクセスする構造メンバーの間のピリオドとしてコーディングされます。 キーワード *struct を使用して、構造タイプの変数を定義します。 次の例は、プログラムで構造を使用する方法を示しています-
#include <stdio.h>
#include <string.h>
struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main( ) {
struct Books Book1; /*Declare Book1 of type Book*/
struct Books Book2; /*Declare Book2 of type Book*/
/*book 1 specification*/
strcpy( Book1.title, "C Programming");
strcpy( Book1.author, "Nuha Ali");
strcpy( Book1.subject, "C Programming Tutorial");
Book1.book_id = 6495407;
/*book 2 specification*/
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Zara Ali");
strcpy( Book2.subject, "Telecom Billing Tutorial");
Book2.book_id = 6495700;
/*print Book1 info*/
printf( "Book 1 title : %s\n", Book1.title);
printf( "Book 1 author : %s\n", Book1.author);
printf( "Book 1 subject : %s\n", Book1.subject);
printf( "Book 1 book_id : %d\n", Book1.book_id);
/*print Book2 info*/
printf( "Book 2 title : %s\n", Book2.title);
printf( "Book 2 author : %s\n", Book2.author);
printf( "Book 2 subject : %s\n", Book2.subject);
printf( "Book 2 book_id : %d\n", Book2.book_id);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Book 1 title : C Programming
Book 1 author : Nuha Ali
Book 1 subject : C Programming Tutorial
Book 1 book_id : 6495407
Book 2 title : Telecom Billing
Book 2 author : Zara Ali
Book 2 subject : Telecom Billing Tutorial
Book 2 book_id : 6495700
関数の引数としての構造
他の変数またはポインターを渡すのと同じ方法で、構造体を関数の引数として渡すことができます。
#include <stdio.h>
#include <string.h>
struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
};
/*function declaration*/
void printBook( struct Books book );
int main( ) {
struct Books Book1; /*Declare Book1 of type Book*/
struct Books Book2; /*Declare Book2 of type Book*/
/*book 1 specification*/
strcpy( Book1.title, "C Programming");
strcpy( Book1.author, "Nuha Ali");
strcpy( Book1.subject, "C Programming Tutorial");
Book1.book_id = 6495407;
/*book 2 specification*/
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Zara Ali");
strcpy( Book2.subject, "Telecom Billing Tutorial");
Book2.book_id = 6495700;
/*print Book1 info*/
printBook( Book1 );
/*Print Book2 info*/
printBook( Book2 );
return 0;
}
void printBook( struct Books book ) {
printf( "Book title : %s\n", book.title);
printf( "Book author : %s\n", book.author);
printf( "Book subject : %s\n", book.subject);
printf( "Book book_id : %d\n", book.book_id);
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Book title : C Programming
Book author : Nuha Ali
Book subject : C Programming Tutorial
Book book_id : 6495407
Book title : Telecom Billing
Book author : Zara Ali
Book subject : Telecom Billing Tutorial
Book book_id : 6495700
構造体へのポインター
あなたは他の変数へのポインタを定義するのと同じ方法で構造体へのポインタを定義することができます-
struct Books *struct_pointer;
これで、上記で定義したポインター変数に構造変数のアドレスを保存できます。 構造変数のアドレスを見つけるには、「&amp」を配置します。次のように構造体の名前の前に演算子-
struct_pointer = &Book1;
その構造へのポインタを使用して構造のメンバーにアクセスするには、次のように→演算子を使用する必要があります-
struct_pointer->title;
構造体ポインターを使用して上記の例を書き直しましょう。
#include <stdio.h>
#include <string.h>
struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
};
/*function declaration*/
void printBook( struct Books *book );
int main( ) {
struct Books Book1; /*Declare Book1 of type Book*/
struct Books Book2; /*Declare Book2 of type Book*/
/*book 1 specification*/
strcpy( Book1.title, "C Programming");
strcpy( Book1.author, "Nuha Ali");
strcpy( Book1.subject, "C Programming Tutorial");
Book1.book_id = 6495407;
/*book 2 specification*/
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Zara Ali");
strcpy( Book2.subject, "Telecom Billing Tutorial");
Book2.book_id = 6495700;
/*print Book1 info by passing address of Book1*/
printBook( &Book1 );
/*print Book2 info by passing address of Book2*/
printBook( &Book2 );
return 0;
}
void printBook( struct Books *book ) {
printf( "Book title : %s\n", book->title);
printf( "Book author : %s\n", book->author);
printf( "Book subject : %s\n", book->subject);
printf( "Book book_id : %d\n", book->book_id);
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Book title : C Programming
Book author : Nuha Ali
Book subject : C Programming Tutorial
Book book_id : 6495407
Book title : Telecom Billing
Book author : Zara Ali
Book subject : Telecom Billing Tutorial
Book book_id : 6495700
ビットフィールド
ビットフィールドを使用すると、構造体にデータをパックできます。 これは、メモリまたはデータストレージが貴重な場合に特に便利です。 典型的な例を含める-
- 複数のオブジェクトを機械語にパックします。 e.g. 1ビットフラグは圧縮できます。
- 外部ファイル形式の読み取り-非標準のファイル形式は、たとえば9ビット整数で読み取ることができます。
Cでは、変数の後に:bit lengthを追加することにより、構造定義でこれを行うことができます。 たとえば-
struct packed_struct {
unsigned int f1:1;
unsigned int f2:1;
unsigned int f3:1;
unsigned int f4:1;
unsigned int type:4;
unsigned int my_int:9;
} pack;
ここで、packed_structには6つのメンバーが含まれます。4つの1ビットフラグf1..f3、4ビットタイプ、9ビットmy_intです。
Cは、フィールドの最大長がコンピュータの整数ワード長以下である場合、上記のビットフィールドを可能な限りコンパクトに自動的にパックします。 そうでない場合、一部のコンパイラはフィールドのメモリオーバーラップを許可し、他のコンパイラは次のワードの次のフィールドを保存します。
C-組合
*union* は、Cで使用可能な特別なデータ型であり、同じメモリ位置に異なるデータ型を格納できます。 多くのメンバーでユニオンを定義できますが、常に1つのメンバーのみが値を含むことができます。 ユニオンは、同じメモリ位置を複数の目的に使用する効率的な方法を提供します。
組合の定義
ユニオンを定義するには、構造の定義中と同じ方法で union ステートメントを使用する必要があります。 共用体ステートメントは、プログラムの複数のメンバーを持つ新しいデータ型を定義します。 ユニオン文の形式は次のとおりです-
union [union tag] {
member definition;
member definition;
...
member definition;
} [one or more union variables];
- unionタグ*はオプションであり、各メンバー定義はint iなどの通常の変数定義です。またはfloat f;または他の有効な変数定義。 ユニオンの定義の最後で、最後のセミコロンの前に、1つ以上のユニオン変数を指定できますが、これはオプションです。 ここに、3つのメンバーi、f、およびstrを持つDataという名前のユニオン型を定義する方法があります-
union Data {
int i;
float f;
char str[20];
} data;
現在、 Data 型の変数は、整数、浮動小数点数、または文字列を格納できます。 これは、単一の変数、つまり同じメモリ位置を使用して、複数のタイプのデータを保存できることを意味します。 要件に基づいて、ユニオン内で組み込みまたはユーザー定義のデータ型を使用できます。
ユニオンが占有するメモリは、ユニオンの最大メンバーを保持するのに十分な大きさになります。 たとえば、上記の例では、データ型は20バイトのメモリ空間を占有します。これは、これが文字列で占有できる最大の空間だからです。 次の例は、上記のユニオンが占有する合計メモリサイズを表示します-
#include <stdio.h>
#include <string.h>
union Data {
int i;
float f;
char str[20];
};
int main( ) {
union Data data;
printf( "Memory size occupied by data : %d\n", sizeof(data));
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Memory size occupied by data : 20
組合員へのアクセス
組合のメンバーにアクセスするには、* memberアクセス演算子(。)を使用します。 メンバーアクセス演算子は、ユニオン変数名とアクセスするユニオンメンバー間のピリオドとしてコーディングされます。 キーワード *union を使用して、ユニオン型の変数を定義します。 次の例は、プログラムでユニオンを使用する方法を示しています-
#include <stdio.h>
#include <string.h>
union Data {
int i;
float f;
char str[20];
};
int main( ) {
union Data data;
data.i = 10;
data.f = 220.5;
strcpy( data.str, "C Programming");
printf( "data.i : %d\n", data.i);
printf( "data.f : %f\n", data.f);
printf( "data.str : %s\n", data.str);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
data.i : 1917853763
data.f : 4122360580327794860452759994368.000000
data.str : C Programming
ここでは、変数に割り当てられた最終値がメモリ位置を占有しているため、ユニオンの i および f メンバーの値が破損していることがわかります。これが str メンバーの値が出力される理由です。結構。
さて、同じ例をもう一度見てみましょう。ここでは、ユニオンを持つ主な目的である一度に1つの変数を使用します-
#include <stdio.h>
#include <string.h>
union Data {
int i;
float f;
char str[20];
};
int main( ) {
union Data data;
data.i = 10;
printf( "data.i : %d\n", data.i);
data.f = 220.5;
printf( "data.f : %f\n", data.f);
strcpy( data.str, "C Programming");
printf( "data.str : %s\n", data.str);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
data.i : 10
data.f : 220.500000
data.str : C Programming
ここでは、一度に1つのメンバーが使用されているため、すべてのメンバーが非常にうまく印刷されています。
C-ビットフィールド
あなたのCプログラムには、次のようにステータスと呼ばれる構造にグループ化されたいくつかのTRUE/FALSE変数が含まれていると仮定します-
struct {
unsigned int widthValidated;
unsigned int heightValidated;
} status;
この構造には8バイトのメモリ領域が必要ですが、実際には、各変数に0または1を格納します。 Cプログラミング言語は、このような状況でメモリ空間を利用するより良い方法を提供します。
構造内でこのような変数を使用している場合、変数の幅を定義して、Cコンパイラーにこれらのバイト数のみを使用することを通知できます。 たとえば、上記の構造は次のように書き換えることができます-
struct {
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status;
上記の構造では、ステータス変数用に4バイトのメモリ空間が必要ですが、値の保存に使用されるのは2ビットのみです。
各変数が1ビットの幅を持つ最大32個の変数を使用する場合、ステータス構造も4バイトを使用します。 ただし、33個の変数があるとすぐに、メモリの次のスロットが割り当てられ、8バイトの使用が開始されます。 私たちは概念を理解するために次の例をチェックしましょう-
#include <stdio.h>
#include <string.h>
/*define simple structure*/
struct {
unsigned int widthValidated;
unsigned int heightValidated;
} status1;
/*define a structure with bit fields*/
struct {
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status2;
int main( ) {
printf( "Memory size occupied by status1 : %d\n", sizeof(status1));
printf( "Memory size occupied by status2 : %d\n", sizeof(status2));
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Memory size occupied by status1 : 8
Memory size occupied by status2 : 4
ビットフィールド宣言
ビットフィールドの宣言は、構造内の次の形式を持っています-
struct {
type [member_name] : width ;
};
次の表は、ビットフィールドの変数要素を説明しています-
Sr.No. | Element & Description |
---|---|
1 |
type ビットフィールドの値の解釈方法を決定する整数型。 タイプは、int、signed int、またはunsigned intです。 |
2 |
member_name ビットフィールドの名前。 |
3 |
width ビットフィールドのビット数。 幅は、指定されたタイプのビット幅以下でなければなりません。 |
定義済みの幅で定義された変数は、*ビットフィールド*と呼ばれます。 ビットフィールドには、1ビット以上を保持できます。たとえば、0から7までの値を格納する変数が必要な場合、次のように3ビット幅のビットフィールドを定義できます-
struct {
unsigned int age : 3;
} Age;
上記の構造定義は、年齢変数が値を格納するために3ビットのみを使用することをCコンパイラに指示します。 3ビット以上を使用しようとすると、使用できなくなります。 私たちは次の例を試してみましょう-
#include <stdio.h>
#include <string.h>
struct {
unsigned int age : 3;
} Age;
int main( ) {
Age.age = 4;
printf( "Sizeof( Age ) : %d\n", sizeof(Age) );
printf( "Age.age : %d\n", Age.age );
Age.age = 7;
printf( "Age.age : %d\n", Age.age );
Age.age = 8;
printf( "Age.age : %d\n", Age.age );
return 0;
}
上記のコードがコンパイルされると、警告付きでコンパイルされ、実行されると、次の結果が生成されます-
Sizeof( Age ) : 4
Age.age : 4
Age.age : 7
Age.age : 0
C-typedef
Cプログラミング言語には、 typedef というキーワードが用意されており、これを使用してタイプに新しい名前を付けることができます。 以下は、1バイトの数字に対して用語 BYTE を定義する例です-
typedef unsigned char BYTE;
この型定義の後、識別子BYTEは、型* unsigned char、たとえば*の略語として使用できます。
BYTE b1, b2;
慣例により、これらの定義には大文字が使用され、ユーザーに型名は実際には記号の略語であることを思い出させますが、次のように小文字を使用できます-
typedef unsigned char byte;
*typedef* を使用して、ユーザー定義のデータ型にも名前を付けることができます。 たとえば、構造体でtypedefを使用して新しいデータ型を定義し、そのデータ型を使用して次のように構造体変数を直接定義できます-
#include <stdio.h>
#include <string.h>
typedef struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
} Book;
int main( ) {
Book book;
strcpy( book.title, "C Programming");
strcpy( book.author, "Nuha Ali");
strcpy( book.subject, "C Programming Tutorial");
book.book_id = 6495407;
printf( "Book title : %s\n", book.title);
printf( "Book author : %s\n", book.author);
printf( "Book subject : %s\n", book.subject);
printf( "Book book_id : %d\n", book.book_id);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Book title : C Programming
Book author : Nuha Ali
Book subject : C Programming Tutorial
Book book_id : 6495407
typedef vs #define
#define *は、 *typedef に似ていますが以下の違いがあるさまざまなデータ型のエイリアスを定義するためにも使用されるCディレクティブです-
- typedef は、*#define *を使用して値のエイリアスも定義できる場合にのみ、型にシンボル名を付けることに制限されています。q。、1などを1として定義できます。
- typedef の解釈はコンパイラによって実行されますが、*#define *ステートメントはプリプロセッサによって処理されます。
次の例は、プログラムで#defineを使用する方法を示しています-
#include <stdio.h>
#define TRUE 1
#define FALSE 0
int main( ) {
printf( "Value of TRUE : %d\n", TRUE);
printf( "Value of FALSE : %d\n", FALSE);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Value of TRUE : 1
Value of FALSE : 0
C-入力および出力
- 入力*と言うとき、それはデータをプログラムに送ることを意味します。 入力は、ファイルの形式またはコマンドラインから指定できます。 Cプログラミングには、指定された入力を読み取り、要件に従ってプログラムに入力する組み込み関数のセットが用意されています。
- 出力*と言うとき、画面、プリンター、または任意のファイルにデータを表示することを意味します。 Cプログラミングには、コンピューター画面にデータを出力したり、テキストまたはバイナリファイルに保存したりするための一連の組み込み関数が用意されています。
標準ファイル
Cプログラミングは、すべてのデバイスをファイルとして扱います。 そのため、ディスプレイなどのデバイスはファイルと同じ方法でアドレス指定され、キーボードと画面へのアクセスを提供するプログラムの実行時に次の3つのファイルが自動的に開きます。
Standard File | File Pointer | Device |
---|---|---|
Standard input | stdin | Keyboard |
Standard output | stdout | Screen |
Standard error | stderr | Your screen |
ファイルポインターは、読み取りおよび書き込み目的でファイルにアクセスする手段です。 このセクションでは、画面から値を読み取る方法と、画面に結果を印刷する方法について説明します。
getchar()およびputchar()関数
- int getchar(void)*関数は、画面から次に使用可能な文字を読み取り、整数として返します。 この関数は、一度に1文字のみを読み取ります。 画面から複数の文字を読みたい場合は、ループでこのメソッドを使用できます。
- int putchar(int c)*関数は、渡された文字を画面に表示し、同じ文字を返します。 この関数は、一度に1文字のみを入力します。 画面に複数の文字を表示する場合は、ループでこのメソッドを使用できます。 次の例を確認してください-
#include <stdio.h>
int main( ) {
int c;
printf( "Enter a value :");
c = getchar( );
printf( "\nYou entered: ");
putchar( c );
return 0;
}
上記のコードがコンパイルおよび実行されると、テキストの入力を待機します。 あなたがテキストを入力してEnterキーを押すと、プログラムが進行し、単一の文字のみを読み取り、次のように表示します-
$./a.out
Enter a value : this is test
You entered: t
gets()およびputs()関数
*char* gets(char * s)*関数は、終了改行またはEOF(ファイルの終わり)のいずれかになるまで、 *stdin* から *s* が指すバッファーに行を読み取ります。
*int puts(const char* s)*関数は、文字列 's'および 'a'の末尾の改行を *stdout* に書き込みます。
注: gets()関数の使用は非推奨になりましたが、getsの代わりにlink:/c_standard_library/c_function_fgets [fgets()]を使用する必要があります。
#include <stdio.h>
int main( ) {
char str[100];
printf( "Enter a value :");
gets( str );
printf( "\nYou entered: ");
puts( str );
return 0;
}
上記のコードがコンパイルおよび実行されると、テキストの入力を待機します。 あなたがテキストを入力してEnterキーを押すと、プログラムは続行し、最後まで完全な行を読み取り、次のように表示します-
$./a.out
Enter a value : this is test
You entered: this is test
scanf()およびprintf()関数
*int scanf(const char* format、...)*関数は、標準入力ストリーム *stdin* から入力を読み取り、提供された *format* に従ってその入力をスキャンします。
*int printf(const char* format、...)*関数は、出力を標準出力ストリーム *stdout* に書き込み、提供された形式に従って出力を生成します。
*format* は単純な定数文字列にすることができますが、%s、%d、%c、%fなどを指定して、文字列、整数、文字、または浮動小数点をそれぞれ印刷または読み取ることができます。 要件に基づいて使用できる他の多くのフォーマットオプションがあります。 概念をよりよく理解するために簡単な例を進めましょう-
#include <stdio.h>
int main( ) {
char str[100];
int i;
printf( "Enter a value :");
scanf("%s %d", str, &i);
printf( "\nYou entered: %s %d ", str, i);
return 0;
}
上記のコードがコンパイルおよび実行されると、テキストの入力を待機します。 あなたがテキストを入力してEnterキーを押すと、プログラムは続行し、入力を読み取り、次のように表示します-
$./a.out
Enter a value : seven 7
You entered: seven 7
ここで、scanf()は、%sおよび%dを指定したのと同じ形式の入力を想定しているため、「文字列整数」などの有効な入力を指定する必要があることに注意してください。 「string string」または「integer integer」を指定すると、誤った入力と見なされます。 第二に、文字列の読み取り中に、scanf()はスペースに遭遇するとすぐに読み取りを停止するため、「this is test」はscanf()の3つの文字列です。
C-ファイルI/O
最後の章では、Cプログラミング言語で処理される標準入出力デバイスについて説明しました。 この章では、Cプログラマがデータストレージ用のテキストファイルまたはバイナリファイルを作成、開く、閉じる方法について説明します。
ファイルは、テキストファイルまたはバイナリファイルに関係なく、バイトシーケンスを表します。 Cプログラミング言語は、ストレージデバイス上のファイルを処理するための低レベル(OSレベル)呼び出しだけでなく、高レベル関数へのアクセスを提供します。 この章では、ファイル管理の重要な呼び出しについて説明します。
ファイルを開く
- fopen()関数を使用して、新しいファイルを作成したり、既存のファイルを開くことができます。 この呼び出しは、ストリームを制御するために必要なすべての情報を含む *FILE 型のオブジェクトを初期化します。 この関数呼び出しのプロトタイプは次のとおりです-
FILE *fopen( const char *filename, const char* mode );
ここで、*ファイル名*は文字列リテラルであり、ファイルに名前を付けるために使用します。アクセス*モード*は次のいずれかの値を持つことができます-
Sr.No. | Mode & Description |
---|---|
1 |
r 読み取り用に既存のテキストファイルを開きます。 |
2 |
w 書き込み用のテキストファイルを開きます。 存在しない場合は、新しいファイルが作成されます。 ここで、プログラムはファイルの先頭からコンテンツの書き込みを開始します。 |
3 |
a 追加モードで書き込むためにテキストファイルを開きます。 存在しない場合は、新しいファイルが作成されます。 ここで、プログラムは既存のファイルコンテンツにコンテンツを追加し始めます。 |
4 |
r+ 読み取りと書き込みの両方のためにテキストファイルを開きます。 |
5 |
w+ 読み取りと書き込みの両方のためにテキストファイルを開きます。 ファイルが存在する場合は最初にファイルの長さをゼロに切り捨て、存在しない場合はファイルを作成します。 |
6 |
a+ 読み取りと書き込みの両方のためにテキストファイルを開きます。 ファイルが存在しない場合は作成します。 読み取りは最初から開始されますが、書き込みは追加のみ可能です。 |
バイナリファイルを処理する場合は、上記のアクセスモードの代わりに次のアクセスモードを使用します-
"rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b"
ファイルを閉じる
ファイルを閉じるには、fclose()関数を使用します。 この関数のプロトタイプは-
int fclose( FILE *fp );
- fclose(-)関数は成功すると0を返し、ファイルを閉じるときにエラーが発生した場合は *EOF を返します。 この関数は、バッファ内でまだ保留中のデータをファイルに実際にフラッシュし、ファイルを閉じて、ファイルに使用されているメモリを解放します。 EOFは、ヘッダーファイル stdio.h で定義されている定数です。
ファイルを1文字ずつ、または固定長文字列の形式で読み書きするために、C標準ライブラリによって提供されるさまざまな関数があります。
ファイルを書く
以下は、個々の文字をストリームに書き込むための最も簡単な機能です-
int fputc( int c, FILE *fp );
関数* fputc()は、引数cの文字値をfpが参照する出力ストリームに書き込みます。 成功すると書き込まれた文字を返します。エラーがある場合は *EOF を返します。 次の関数を使用して、ヌル終了文字列をストリームに書き込むことができます-
int fputs( const char *s, FILE *fp );
関数* fputs()は、文字列 *s をfpによって参照される出力ストリームに書き込みます。 成功すると負でない値を返します。そうでない場合は、エラーの場合に EOF が返されます。 int fprintf(FILE fp、const char * format、…)*関数も使用して、文字列をファイルに書き込むことができます。 次の例を試してください。
*/tmp* ディレクトリが使用可能であることを確認してください。 そうでない場合は、次に進む前に、マシンにこのディレクトリを作成する必要があります。
#include <stdio.h>
main() {
FILE *fp;
fp = fopen("/tmp/test.txt", "w+");
fprintf(fp, "This is testing for fprintf...\n");
fputs("This is testing for fputs...\n", fp);
fclose(fp);
}
上記のコードをコンパイルして実行すると、/tmpディレクトリに新しいファイル test.txt が作成され、2つの異なる関数を使用して2行が書き込まれます。 次のセクションでこのファイルを読みましょう。
ファイルを読む
以下から、ファイルから単一の文字を読み取るための最も簡単な機能が与えられます-
int fgetc( FILE * fp );
- fgetc()関数は、fpによって参照される入力ファイルから文字を読み取ります。 戻り値は読み取られた文字であり、エラーの場合は *EOF を返します。 次の関数は、ストリームから文字列を読み取ることができます-
char *fgets( char *buf, int n, FILE *fp );
関数* fgets()は、fpによって参照される入力ストリームから最大n-1文字を読み取ります。 読み取った文字列をバッファ *buf にコピーし、文字列を終了するために null 文字を追加します。
この関数は、最大文字数を読み取る前に改行文字「\ n」またはファイルのEOFの終わりを検出すると、改行文字を含むその時点までに読み取られた文字のみを返します。 int fscanf(FILE fp、const char * format、…)*関数を使用してファイルから文字列を読み取ることもできますが、最初のスペース文字が検出されると読み取りを停止します。
#include <stdio.h>
main() {
FILE *fp;
char buff[255];
fp = fopen("/tmp/test.txt", "r");
fscanf(fp, "%s", buff);
printf("1 : %s\n", buff );
fgets(buff, 255, (FILE*)fp);
printf("2: %s\n", buff );
fgets(buff, 255, (FILE*)fp);
printf("3: %s\n", buff );
fclose(fp);
}
上記のコードがコンパイルおよび実行されると、前のセクションで作成されたファイルを読み取り、次の結果を生成します-
1 : This
2: is testing for fprintf...
3: This is testing for fputs...
ここで何が起こったかについてもう少し詳しく見てみましょう。 最初に、* fscanf()は *This のみを読み取ります。その後、スペースに遭遇したため、2番目の呼び出しは* fgets()のためであり、行末に達するまで残りの行を読み取ります。 最後に、最後の呼び出し fgets()*は2行目を完全に読み取ります。
バイナリI/O関数
バイナリ入出力に使用できる2つの機能があります-
size_t fread(void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
size_t fwrite(const void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
これらの関数は両方とも、メモリのブロック(通常は配列または構造)の読み取りまたは書き込みに使用する必要があります。
C-プリプロセッサー
- Cプリプロセッサ*はコンパイラの一部ではありませんが、コンパイルプロセスの別のステップです。 簡単に言えば、Cプリプロセッサは単なるテキスト置換ツールであり、実際のコンパイルの前に必要な前処理を行うようコンパイラに指示します。 CプリプロセッサをCPPと呼びます。
すべてのプリプロセッサコマンドは、ハッシュ記号(#)で始まります。 最初の非空白文字である必要があります。読みやすくするために、プリプロセッサディレクティブは最初の列から開始する必要があります。 次のセクションでは、すべての重要なプリプロセッサディレクティブをリストします-
Sr.No. | Directive & Description |
---|---|
1 |
#define プリプロセッサマクロを置き換えます。 |
2 |
#include 別のファイルから特定のヘッダーを挿入します。 |
3 |
#undef プリプロセッサマクロの定義を解除します。 |
4 |
#ifdef このマクロが定義されている場合、trueを返します。 |
5 |
#ifndef このマクロが定義されていない場合、trueを返します。 |
6 |
#if コンパイル時の条件が真かどうかをテストします。 |
7 |
#else
|
8 |
#elif
|
9 |
#endif プリプロセッサー条件付きを終了します。 |
10 |
#error エラーメッセージを標準エラー出力に出力します。 |
11 |
#pragma 標準化された方法を使用して、コンパイラに特別なコマンドを発行します。 |
プリプロセッサの例
以下の例を分析して、さまざまなディレクティブを理解してください。
#define MAX_ARRAY_LENGTH 20
このディレクティブは、MAX_ARRAY_LENGTHのインスタンスを20に置き換えるようにCPPに指示します。 定数に_#define_を使用して、読みやすくします。
#include <stdio.h>
#include "myheader.h"
これらのディレクティブは、CPPに System Libraries からstdio.hを取得し、現在のソースファイルにテキストを追加するように指示します。 次の行は、CPPにローカルディレクトリから myheader.h を取得し、現在のソースファイルにコンテンツを追加するよう指示します。
#undef FILE_SIZE
#define FILE_SIZE 42
既存のFILE_SIZEの定義を解除し、42として定義するようにCPPに指示します。
#ifndef MESSAGE
#define MESSAGE "You wish!"
#endif
MESSAGEがまだ定義されていない場合にのみ、MESSAGEを定義するようにCPPに指示します。
#ifdef DEBUG
/*Your debugging statements here*/
#endif
DEBUGが定義されている場合、囲まれたステートメントを処理するようにCPPに指示します。 これは、コンパイル時に_-DDEBUG_フラグをgccコンパイラーに渡す場合に便利です。 これによりDEBUGが定義されるため、コンパイル中にオンザフライでデバッグをオンまたはオフにできます。
定義済みマクロ
ANSI Cは多くのマクロを定義しています。 それぞれをプログラミングで使用できますが、事前定義されたマクロを直接変更しないでください。
Sr.No. | Macro & Description |
---|---|
1 |
DATE 「MMM DD YYYY」形式の文字リテラルとしての現在の日付。 |
2 |
TIME 「HH:MM:SS」形式の文字リテラルとしての現在時刻。 |
3 |
FILE これには、現在のファイル名が文字列リテラルとして含まれています。 |
4 |
LINE これには、10進定数として現在の行番号が含まれます。 |
5 |
STDC コンパイラがANSI標準に準拠する場合、1として定義されます。 |
次の例を試してみましょう-
#include <stdio.h>
int main() {
printf("File :%s\n", __FILE__ );
printf("Date :%s\n", __DATE__ );
printf("Time :%s\n", __TIME__ );
printf("Line :%d\n", __LINE__ );
printf("ANSI :%d\n", __STDC__ );
}
ファイル test.c の上記のコードがコンパイルされ実行されると、次の結果が生成されます-
File :test.c
Date :Jun 2 2012
Time :03:36:24
Line :8
ANSI :1
プリプロセッサ演算子
Cプリプロセッサは、マクロの作成に役立つ次の演算子を提供しています-
マクロ継続(\)演算子
通常、マクロは1行に限定されます。 マクロ継続演算子(\)は、1行には長すぎるマクロを継続するために使用されます。 たとえば-
#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")
文字列化(#)演算子
文字列化演算子または番号記号演算子( '#')をマクロ定義内で使用すると、マクロパラメーターが文字列定数に変換されます。 この演算子は、指定された引数またはパラメーターリストを持つマクロでのみ使用できます。 たとえば-
#include <stdio.h>
#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")
int main(void) {
message_for(Carole, Debra);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Carole and Debra: We love you!
トークンの貼り付け(##)演算子
マクロ定義内のトークン貼り付け演算子(##)は、2つの引数を組み合わせます。 マクロ定義内の2つの別個のトークンを単一のトークンに結合できます。 たとえば-
#include <stdio.h>
#define tokenpaster(n) printf ("token" #n " = %d", token##n)
int main(void) {
int token34 = 40;
tokenpaster(34);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
token34 = 40
この例は、プリプロセッサから次の実際の出力になるため、そうなりました-
printf ("token34 = %d", token34);
この例では、token ## nのtoken34への連結を示しています。ここでは、 stringize と token-pasting の両方を使用しています。
Defined()演算子
プリプロセッサの defined 演算子は、定数式で使用され、#defineを使用して識別子が定義されているかどうかを判断します。 指定された識別子が定義されている場合、値はtrue(ゼロ以外)です。 シンボルが定義されていない場合、値はfalse(ゼロ)です。 定義された演算子は次のように指定されます-
#include <stdio.h>
#if !defined (MESSAGE)
#define MESSAGE "You wish!"
#endif
int main(void) {
printf("Here is the message: %s\n", MESSAGE);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Here is the message: You wish!
パラメータ化されたマクロ
CPPの強力な機能の1つは、パラメーター化されたマクロを使用して機能をシミュレートする機能です。 たとえば、次のように数値を二乗するコードがあります-
int square(int x) {
return x *x;
}
私たちは次のようにマクロを使用してコードの上に書き換えることができます-
#define square(x) ((x)* (x))
引数を持つマクロは、使用する前に*#define *ディレクティブを使用して定義する必要があります。 引数リストは括弧で囲まれ、マクロ名の直後になければなりません。 マクロ名と左括弧の間にスペースは使用できません。 たとえば-
#include <stdio.h>
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void) {
printf("Max between 20 and 10 is %d\n", MAX(10, 20));
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Max between 20 and 10 is 20
C-ヘッダーファイル
ヘッダーファイルは、拡張子が .h のファイルであり、複数のソースファイル間で共有されるC関数宣言とマクロ定義が含まれています。 ヘッダーファイルには2つのタイプがあります。プログラマが書き込むファイルと、コンパイラに付属するファイルです。
コンパイラーに付属している stdio.h ヘッダーファイルを含めるように、Cプリプロセスディレクティブ*#include *にヘッダーファイルを含めることで、ヘッダーファイルをプログラムで使用することを要求します。
ヘッダーファイルを含めることはヘッダーファイルのコンテンツをコピーすることと同じですが、エラーが発生しやすく、特にソースファイルにヘッダーファイルのコンテンツをコピーすることはお勧めできません。プログラムに複数のソースファイルがあります。
CまたはC ++プログラムの簡単なプラクティスは、すべての定数、マクロ、システム全体のグローバル変数、および関数プロトタイプをヘッダーファイルに保持し、必要に応じてそのヘッダーファイルを含めることです。
構文を含める
ユーザーとシステムの両方のヘッダーファイルは、前処理ディレクティブ*#include *を使用してインクルードされます。 次の2つの形式があります-
#include <file>
この形式は、システムヘッダーファイルに使用されます。 システムディレクトリの標準リストで「file」という名前のファイルを検索します。 ソースコードのコンパイル中に-Iオプションを使用して、このリストの先頭にディレクトリを追加できます。
#include "file"
このフォームは、独自のプログラムのヘッダーファイルに使用されます。 現在のファイルを含むディレクトリで「file」という名前のファイルを検索します。 ソースコードのコンパイル中に-Iオプションを使用して、このリストの先頭にディレクトリを追加できます。
操作を含める
#include *ディレクティブは、現在のソースファイルの残りの部分を続行する前に、指定されたファイルを入力としてスキャンするようにCプリプロセッサに指示することで機能します。 プリプロセッサからの出力には、既に生成された出力、インクルードファイルからの出力、#include *ディレクティブの後のテキストからの出力が含まれます。 たとえば、次のようにヘッダーファイルheader.hがある場合-
char *test (void);
このようなヘッダーファイルを使用する_program.c_と呼ばれるメインプログラム-
int x;
#include "header.h"
int main (void) {
puts (test ());
}
コンパイラは、program.cが読み取る場合と同じトークンストリームを参照します。
int x;
char *test (void);
int main (void) {
puts (test ());
}
一度だけのヘッダー
ヘッダーファイルが2回インクルードされると、コンパイラはその内容を2回処理し、エラーが発生します。 これを防ぐ標準的な方法は、次のように、ファイルの実際の内容全体を条件付きで囲むことです-
#ifndef HEADER_FILE
#define HEADER_FILE
the entire header file file
#endif
この構成体は、一般にラッパー*#ifndef *として知られています。 ヘッダーが再び含まれる場合、HEADER_FILEが定義されているため、条件はfalseになります。 プリプロセッサーはファイルの内容全体をスキップし、コンパイラーはそれを2回表示しません。
計算されたインクルード
場合によっては、いくつかの異なるヘッダーファイルの1つを選択してプログラムに含める必要があります。 たとえば、さまざまな種類のオペレーティングシステムで使用される構成パラメーターを指定する場合があります。 次のように一連の条件付きでこれを行うことができます-
#if SYSTEM_1
# include "system_1.h"
#elif SYSTEM_2
# include "system_2.h"
#elif SYSTEM_3
...
#endif
しかし、成長するにつれて退屈になり、代わりにプリプロセッサはヘッダー名にマクロを使用する機能を提供します。 これは、*計算済みインクルード*と呼ばれます。 *#include *の直接引数としてヘッダー名を書く代わりに、単にそこにマクロ名を入れます-
#define SYSTEM_H "system_1.h"
...
#include SYSTEM_H
SYSTEM_Hが展開され、プリプロセッサはsystem_1.hを、*#include *が元々そのように記述されているかのように探します。 SYSTEM_Hは、Makefileで-Dオプションを使用して定義できます。
C-タイプ鋳造
あるデータ型を別のデータ型に変換することは、型キャストまたは型変換と呼ばれます。 たとえば、「long」値を単純な整数に格納する場合は、「long」を「int」にキャストできます。 次のように*キャスト演算子*を使用して明示的に値を1つのタイプから別のタイプに変換できます-
(type_name) expression
キャスト演算子が別の整数変数の除算を浮動小数点演算として実行する次の例を考えてください-
#include <stdio.h>
main() {
int sum = 17, count = 5;
double mean;
mean = (double) sum/count;
printf("Value of mean : %f\n", mean );
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Value of mean : 3.400000
ここで、キャスト演算子は除算よりも優先されるため、 sum の値は最初に double 型に変換され、最後にcountで除算されてdouble値が生成されることに注意してください。
型変換は、コンパイラーによって自動的に実行される暗黙的なものにすることも、* cast演算子*を使用して明示的に指定することもできます。 型変換が必要な場合は、キャスト演算子を使用することをお勧めします。
整数プロモーション
整数プロモーションは、整数型の値が int または unsigned int よりも小さい値が int または unsigned int に変換されるプロセスです。 整数で文字を追加する例を考えてみましょう-
#include <stdio.h>
main() {
int i = 17;
char c = 'c';/*ascii value is 99*/
int sum;
sum = i + c;
printf("Value of sum : %d\n", sum );
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Value of sum : 116
ここで、コンパイラは整数の昇格を行い、実際の加算操作を実行する前に 'c’の値をASCIIに変換しているため、sumの値は116です。
通常の算術変換
- 通常の算術変換*は、それらの値を共通の型にキャストするために暗黙的に実行されます。 コンパイラーは最初に_整数プロモーション_を実行します。オペランドがまだ異なる型を持っている場合、それらは次の階層で最高に表示される型に変換されます-
通常の算術変換は、代入演算子に対しても、論理演算子&&および||に対しても実行されません。 私たちは概念を理解するために次の例を取り上げましょう-
#include <stdio.h>
main() {
int i = 17;
char c = 'c';/*ascii value is 99*/
float sum;
sum = i + c;
printf("Value of sum : %f\n", sum );
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Value of sum : 116.000000
ここでは、最初のcが整数に変換されることを理解するのは簡単ですが、最終値がdoubleであるため、通常の算術変換が適用され、コンパイラーはiとcを 'float’に変換し、それらを加算して 'float’結果を生成します。
C-エラー処理
そのため、Cプログラミングはエラー処理を直接サポートしていませんが、システムプログラミング言語であるため、戻り値の形式で低レベルでアクセスできます。 CまたはUnix関数呼び出しのほとんどは、エラーが発生した場合に-1またはNULLを返し、エラーコード errno を設定します。 グローバル変数として設定され、関数呼び出し中にエラーが発生したことを示します。 <error.h>ヘッダーファイルで定義されているさまざまなエラーコードを見つけることができます。
そのため、Cプログラマーは戻り値を確認し、戻り値に応じて適切なアクションを実行できます。 プログラムの初期化時にerrnoを0に設定することをお勧めします。 値0は、プログラムにエラーがないことを示します。
errno、perror()。 およびstrerror()
Cプログラミング言語は、 errno に関連付けられたテキストメッセージを表示するために使用できる* perror()および strerror()*関数を提供します。
- * perror()*関数は、渡された文字列を表示し、その後にコロン、スペース、そして現在のerrno値のテキスト表現が続きます。
- * strerror()*関数。現在のerrno値のテキスト表現へのポインターを返します。
エラー状態をシミュレートして、存在しないファイルを開いてみましょう。 ここでは、両方の機能を使用して使用方法を示していますが、エラーを出力する1つ以上の方法を使用できます。 2つ目の重要な点は、 stderr ファイルストリームを使用してすべてのエラーを出力する必要があることです。
#include <stdio.h>
#include <errno.h>
#include <string.h>
extern int errno ;
int main () {
FILE * pf;
int errnum;
pf = fopen ("unexist.txt", "rb");
if (pf == NULL) {
errnum = errno;
fprintf(stderr, "Value of errno: %d\n", errno);
perror("Error printed by perror");
fprintf(stderr, "Error opening file: %s\n", strerror( errnum ));
} else {
fclose (pf);
}
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Value of errno: 2
Error printed by perror: No such file or directory
Error opening file: No such file or directory
ゼロエラーで除算する
一般的な問題は、任意の数を分割するときに、プログラマが除数がゼロであるかどうかをチェックせず、最終的に実行時エラーが発生することです。
以下のコードは、除算する前に除数がゼロかどうかを確認することでこれを修正します-
#include <stdio.h>
#include <stdlib.h>
main() {
int dividend = 20;
int divisor = 0;
int quotient;
if( divisor == 0){
fprintf(stderr, "Division by zero! Exiting...\n");
exit(-1);
}
quotient = dividend/divisor;
fprintf(stderr, "Value of quotient : %d\n", quotient );
exit(0);
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Division by zero! Exiting...
プログラム終了ステータス
操作が成功した後にプログラムが出てくる場合、EXIT_SUCCESSの値で終了するのが一般的な方法です。 ここで、EXIT_SUCCESSはマクロであり、0として定義されています。
プログラムにエラー状態があり、出てくる場合は、-1として定義されたステータスEXIT_FAILUREで終了する必要があります。 次のように上記のプログラムを書いてみましょう-
#include <stdio.h>
#include <stdlib.h>
main() {
int dividend = 20;
int divisor = 5;
int quotient;
if( divisor == 0) {
fprintf(stderr, "Division by zero! Exiting...\n");
exit(EXIT_FAILURE);
}
quotient = dividend/divisor;
fprintf(stderr, "Value of quotient : %d\n", quotient );
exit(EXIT_SUCCESS);
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Value of quotient : 4
C-再帰
再帰は、自己相似の方法でアイテムを繰り返すプロセスです。 プログラミング言語では、プログラムで同じ関数内の関数を呼び出すことができる場合、その関数の再帰呼び出しと呼ばれます。
void recursion() {
recursion();/*function calls itself*/
}
int main() {
recursion();
}
Cプログラミング言語は、再帰、つまり自分自身を呼び出す関数をサポートしています。 ただし、再帰を使用する場合、プログラマは関数から終了条件を定義するように注意する必要があります。定義しないと、無限ループに陥ります。
再帰関数は、数値の階乗の計算、フィボナッチ数列の生成など、多くの数学的な問題を解決するのに非常に役立ちます。
階乗
次の例では、再帰関数を使用して、与えられた数の階乗を計算します-
#include <stdio.h>
unsigned long long int factorial(unsigned int i) {
if(i <= 1) {
return 1;
}
return i * factorial(i - 1);
}
int main() {
int i = 12;
printf("Factorial of %d is %d\n", i, factorial(i));
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
Factorial of 12 is 479001600
フィボナッチシリーズ
次の例では、再帰関数を使用して、指定された数のフィボナッチ数列を生成します-
#include <stdio.h>
int fibonacci(int i) {
if(i == 0) {
return 0;
}
if(i == 1) {
return 1;
}
return fibonacci(i-1) + fibonacci(i-2);
}
int main() {
int i;
for (i = 0; i < 10; i++) {
printf("%d\t\n", fibonacci(i));
}
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
0
1
1
2
3
5
8
13
21
34
C-可変引数
場合によっては、事前定義された数のパラメーターではなく、可変数の引数、つまりパラメーターを取ることができる関数が必要な状況に出くわすことがあります。 Cプログラミング言語はこの状況に対するソリューションを提供し、要件に基づいて可変数のパラメーターを受け入れることができる関数を定義できます。 次の例は、このような関数の定義を示しています。
int func(int, ... ) {
.
.
.
}
int main() {
func(1, 2, 3);
func(1, 2, 3, 4);
}
関数* func()の最後の引数は楕円であることに注意してください。 3つのドット( *… )と楕円の直前のドットは、常に渡された変数引数の総数を表す int です。 このような機能を使用するには、変数引数の機能を実装し、指定された手順に従うための機能とマクロを提供する stdarg.h ヘッダーファイルを使用する必要があります-
- 最後のパラメーターを楕円として定義し、楕円の直前のパラメーターは常に引数の数を表す int です。
- 関数定義に va_list 型変数を作成します。 このタイプは、stdarg.hヘッダーファイルで定義されています。
- int パラメーターと va_start マクロを使用して、 va_list 変数を引数リストに初期化します。 マクロva_startは、stdarg.hヘッダーファイルで定義されています。
- va_arg マクロと va_list 変数を使用して、引数リストの各項目にアクセスします。
- マクロ va_end を使用して、 va_list 変数に割り当てられたメモリをクリーンアップします。
今、私たちは上記の手順に従って、パラメータの可変数を取り、それらの平均を返すことができる簡単な関数を書き留めましょう-
#include <stdio.h>
#include <stdarg.h>
double average(int num,...) {
va_list valist;
double sum = 0.0;
int i;
/*initialize valist for num number of arguments*/
va_start(valist, num);
/*access all the arguments assigned to valist*/
for (i = 0; i < num; i++) {
sum += va_arg(valist, int);
}
/*clean memory reserved for valist*/
va_end(valist);
return sum/num;
}
int main() {
printf("Average of 2, 3, 4, 5 = %f\n", average(4, 2,3,4,5));
printf("Average of 5, 10, 15 = %f\n", average(3, 5,10,15));
}
上記のコードをコンパイルして実行すると、次の結果が生成されます。 関数* average()*が2回呼び出され、最初の引数が渡される変数引数の総数を表すことに注意してください。 可変長の引数を渡すために楕円のみが使用されます。
Average of 2, 3, 4, 5 = 3.500000
Average of 5, 10, 15 = 10.000000
C-メモリ管理
この章では、Cでの動的メモリ管理について説明します。 Cプログラミング言語は、メモリの割り当てと管理のためのいくつかの機能を提供します。 これらの関数は、 <stdlib.h> ヘッダーファイルにあります。
Sr.No. | Function & Description |
---|---|
1 |
void *calloc(int num, int size); この関数は、バイト単位のサイズが size になる num 要素の配列を割り当てます。 |
2 |
void free(void *address); この関数は、アドレスで指定されたメモリブロックのブロックを解放します。 |
3 |
void *malloc(int num); この関数は、 num バイトの配列を割り当て、初期化せずに残します。 |
4 |
void *realloc(void *address, int newsize); この関数は、 newsize まで拡張してメモリを再割り当てします。 |
メモリを動的に割り当てる
プログラミング中に、配列のサイズを知っている場合、それは簡単であり、配列として定義できます。 たとえば、任意の人の名前を保存するには、最大100文字まで入力できるため、次のように定義できます-
char name[100];
しかし、ここで、保存する必要のあるテキストの長さがわからない状況を考えてみましょう。たとえば、トピックに関する詳細な説明を保存したい場合です。 ここで、必要なメモリ量を定義せずに文字へのポインタを定義する必要があり、後で要件に基づいて、以下の例に示すようにメモリを割り当てることができます-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char name[100];
char *description;
strcpy(name, "Zara Ali");
/*allocate memory dynamically*/
description = malloc( 200 * sizeof(char) );
if( description == NULL ) {
fprintf(stderr, "Error - unable to allocate required memory\n");
} else {
strcpy( description, "Zara ali a DPS student in class 10th");
}
printf("Name = %s\n", name );
printf("Description: %s\n", description );
}
上記のコードをコンパイルして実行すると、次の結果が生成されます。
Name = Zara Ali
Description: Zara ali a DPS student in class 10th
同じプログラムは、 calloc(); を使用して記述できます。次のように、mallocをcallocに置き換える必要があるのは、ただ-
calloc(200, sizeof(char));
したがって、完全に制御でき、サイズを一度定義すると変更できないアレイとは異なり、メモリの割り当て中に任意のサイズ値を渡すことができます。
メモリのサイズ変更と解放
プログラムが出てくると、オペレーティングシステムはプログラムによって割り当てられたすべてのメモリを自動的に解放しますが、メモリが不要になった場合は、* free()*関数を呼び出してそのメモリを解放することをお勧めします。
または、関数* realloc()*を呼び出して、割り当てられたメモリブロックのサイズを増減できます。 上記のプログラムをもう一度確認し、realloc()およびfree()関数を使用してみましょう-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char name[100];
char *description;
strcpy(name, "Zara Ali");
/*allocate memory dynamically*/
description = malloc( 30 * sizeof(char) );
if( description == NULL ) {
fprintf(stderr, "Error - unable to allocate required memory\n");
} else {
strcpy( description, "Zara ali a DPS student.");
}
/*suppose you want to store bigger description*/
description = realloc( description, 100 * sizeof(char) );
if( description == NULL ) {
fprintf(stderr, "Error - unable to allocate required memory\n");
} else {
strcat( description, "She is in class 10th");
}
printf("Name = %s\n", name );
printf("Description: %s\n", description );
/*release memory using free() function*/
free(description);
}
上記のコードをコンパイルして実行すると、次の結果が生成されます。
Name = Zara Ali
Description: Zara ali a DPS student.She is in class 10th
余分なメモリを再割り当てせずに上記の例を試すことができます。説明に利用可能なメモリがないため、strcat()関数はエラーを返します。
C-コマンドライン引数
実行時にコマンドラインからCプログラムにいくつかの値を渡すことができます。 これらの値は*コマンドライン引数*と呼ばれ、特にコード内でこれらの値をハードコーディングするのではなく、外部からプログラムを制御する場合、プログラムにとって重要です。
コマンドライン引数はmain()関数引数を使用して処理されます。 argc は渡された引数の数を指し、 argv [] はプログラムに渡された各引数を指すポインター配列です。 以下は、コマンドラインから提供された引数があるかどうかをチェックし、それに応じてアクションを取る簡単な例です-
#include <stdio.h>
int main( int argc, char *argv[] ) {
if( argc == 2 ) {
printf("The argument supplied is %s\n", argv[1]);
}
else if( argc > 2 ) {
printf("Too many arguments supplied.\n");
}
else {
printf("One argument expected.\n");
}
}
上記のコードをコンパイルして単一の引数で実行すると、次の結果が生成されます。
$./a.out testing
The argument supplied is testing
上記のコードが2つの引数を使用してコンパイルおよび実行されると、次の結果が生成されます。
$./a.out testing1 testing2
Too many arguments supplied.
引数を渡さずに上記のコードをコンパイルして実行すると、次の結果が生成されます。
$./a.out
One argument expected
*argv [0]* はプログラム自体の名前を保持し、 *argv [1]* は指定された最初のコマンドライン引数へのポインターであり、* argv [n]は最後の引数であることに注意してください。 引数が指定されていない場合、argcは1になります。1つの引数を渡すと、 *argc* は2に設定されます。
すべてのコマンドライン引数をスペースで区切って渡しますが、引数自体にスペースがある場合は、二重引用符 ""または単一引用符 で囲んで引数を渡すことができます。 上記の例をもう一度書き直して、プログラム名を出力し、二重引用符で囲んでコマンドライン引数を渡します-
#include <stdio.h>
int main( int argc, char *argv[] ) {
printf("Program name %s\n", argv[0]);
if( argc == 2 ) {
printf("The argument supplied is %s\n", argv[1]);
}
else if( argc > 2 ) {
printf("Too many arguments supplied.\n");
}
else {
printf("One argument expected.\n");
}
}
上記のコードをコンパイルし、スペースで区切られた単一の引数を使用して二重引用符で囲んで実行すると、次の結果が生成されます。
$./a.out "testing1 testing2"
Progranm name ./a.out
The argument supplied is testing1 testing2