C言語

目次

基本的な命令、ライブラリの使い方を確認することを目的としたプログラム例を載せています。

1.動作環境(サンプルの実行環境)
・VirtualBoxのCentOs7マシン
・CentOsのバージョン
# cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)
・コンパイラのバージョン
【cコンパイラ】
・パッケージ一覧
# yum list | grep gcc

・インストール
# yum -y install gcc
・バージョン確認
# gcc –version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

2.Cについて

(1)歴史
1972年、ベル研、Dennis Ritchieによって設計された。cは、科学技術計算などの問題を解決するための問題指向型(高級言語)に対して、コンピュータを動かすための言語として設計(機械指向型言語、低級言語)されたが、コンピュータの細部を意識しないで使えるので、低級以上、高級以下の位置づけの言語。

(2)プログラムのソースファイル作成から実行形式にするまでの流れ

gcc オプション
-Wall: gcc に 詳細なWarning を出力
-o file: 出力先をfileに指定
-v: コンパイルの各ステージで実行されるコマンドを表示する
-c: コンパイルのみ行い、リンクは行なわない
-S: コンパイルが終ったところで処理を中断する

(3)言語規格
・C90『JIS X 3010:1996 プログラム言語C』で規定されるC言語規格
・C99『JIS X 3010:2003 プログラム言語C』で規定されるC言語規格
・C11 C99の後継として、2011年に制定されたISO/IEC 9899:2011で規定されるC言語規格。最新の規格。
・MISRA C
 英国The Motor Industry Software Reliability Association(MISRA)によって定められた、C言語のコーディングガイドライン

3.Cプログラムのサンプル

3.1 サンプル1
 main()関数で構造体のメンバに値を設定して、値を出力する関数を呼んで表示するプログラム。1つのソースファイルに実装する場合と、2つのファイルに分けて実装する場合の2パターンについて作成する。
(1)1つのファイル(main1.cのみ)で実装する場合

main1.c

#include <stdio.h>

typedef struct _Person{  //構造体宣言
    char * name;
    int age;
}Person;

void send(Person mperson);//プロトタイプ宣言


int main(void){
    Person man1;
    man1.name="satou";
    man1.age=20;
    send(man1);
}

void send(Person mperson){
   printf("name:%s\n",mperson.name);
   printf("age:%d\n",mperson.age);
}

(2)2つのファイル(main2.c,member.c)で実装する場合

main2.c

#include "member.h"

int main(void){
    Person man1;
    man1.name="satou";
    man1.age=20;
    send(man1);
}

member.h

//構造体宣言
typedef struct _Person{
    char * name;
    int age;
}Person;

//プロトタイプ宣言
void send(Person mperson);

(解説)
member.cの関数の利用側で構造体が必要になるため、ヘッダファイルに含める

member.c

#include <stdio.h>
#include "member.h"

void send(Person mperson){
   printf("name:%s\n",mperson.name);
   printf("age:%d\n",mperson.age);
}

(解説)
printf()はこの関数内でのみ使用するため、標準ライブラリのインクルード文はヘッダファイルに入れない。
自分のヘッダファイルを読み込み、コンパイル時にチェックできるようにする。

4.文法とサンプル

4.1 入出力
標準の入出力関数

(1)putchar
stdio.hの中で定義されているマクロ。
仮引数のint型データの下位1バイトを切り出して標準出力に送る。
プロトタイプ int putchar(int)

sample_1.c

#include<stdio.h>
#include<stdlib.h>

int main(){
	int i;
	putchar('A');
	putchar(0x41);//16進
	putchar(65);//10進
  	putchar('\n');

	int a=0x44434241;
	for(i=0;i<4;i++){   //1バイトづつ取り出し
		putchar(a);
		a=a>>8;
		putchar('\n');
	}

	int b=0x44434241;
	putchar(b);
	putchar(b);
	putchar(b);
	putchar(b);
	putchar(b);
	putchar('\n');
  	return 0;
}

(2)printf
標準ライブラリに含まれている関数で、ヘッダファイルから関数の情報(関数プロトタイプ)を読み込む。
プロトタイプ
int printf(const char* format,…);
戻り値:int型 標準出力に渡したバイト数、エラーが発生した場合は負の値
printfは出力用、scanfは入力用に使われ、fは”formatted”で書式付きを表す。
書式は%(変換文字)で指定する。c:文字、d:10進整数、e:科学表記による浮動小数点数、f:浮動小数点数、s:文字列。
表示桁数は<全体の幅>.<小数点以下の幅>で指定。片方だけの指定、又は指定しなくても良い。指定がなければデフォルトが使用。 <小数点以下の幅>は、文字列の場合には最大文字数。

例)printf(“%s”,”abc”);

#include<stdio.h>
int main(void)
{
    printf("%c\n",'A'); 
    printf("-1は、符号付%d 符号無%u 16進%x\n",-1,-1,-1);
    printf("%sは%f\n","円周率", 3.14159); 
    return 0;
}

(3)getchar
stdio.hの中で定義されているマクロ。キーボードからの文字の読み取りに使われる。
プロトタイプ
int getchar(void);
戻り値:int型 受け取った0~255の範囲の値。エラーが起きた場合はEOF(多くの場合-1)を戻す

sample_3.c

#include<stdio.h>
int main(void)
{
        int c;
        c=getchar();
        printf("「%c」の文字コードは十進で%dです\n",c,c);        
        return 0;
}

(4)scanf
標準ライブラリに含まれている関数で、ヘッダファイルから関数の情報(関数プロトタイプ)を読み込む。標準ファイルstdinから文字を読み取る。
プロトタイプ
int scanf(const char *format,…);
戻り値:int型 読み込んだデータの数。エラーが起きた場合はEOF(多くの場合-1)を戻す。
書式は%(変換文字)で指定する。c:文字、d:10進整数、f:浮動小数点数(float)、lf:浮動小数点数(double)、s:文字列。
2個目以降の引数: データを格納するメモリー番地。

sample_2.c

include<stdio.h>

int main(void)
{
	int i;/*データを記憶する変数を用意*/
        double d;/*データを記憶する変数を用意*/

        scanf("%d", &i);/*入力を10進整数として読み、その値を変数iの番地のメモリーにint型で書きこむ*/
        scanf("%lf", &d);/*入力を実数として読み、その値を変数dの番地のメモリーにdouble型で書きこむ*/

        printf("i=%d d=%f \n", i, d);

        return 0;
}

4.2 データ型、演算子

(1)データ型
基本のデータ型は文字型 char 、整数型 int、実数型 float、倍精度実数型 double

データ型名値の範囲
char1バイトの符号付整数。ASCIIコードといった文字コードに使用。
unsigned char1バイトの符号なし整数
short2バイトの符号付整数
unsigned short2バイトの符号なし整数
long4バイトの符号付整数
unsignedlong4バイトの符号なし整数
int2または4バイトの符号付整数(コンパイラに依存)
unsigned 2バイトまた4バイトの符号なし整数(コンパイラに依存)unsigned intは簡略化してunsignedと書ける。
float4バイトの単精度浮動小数点実数
double8バイトの倍精度浮動小数点実数

バイト数と表現できる値(10進数)の範囲
(上段:符号無し/下段:符号有り、2の補数表示)
1バイト(8ビット):0~255
          -128~127
2バイト(16ビット):0~65,535
          -32,768~32,767
4バイト(32ビット):0~4,294,967,295
          -2,147,483,648~2,147,483,647
8バイト(64ビット):0~18,446,744,073,709,551,615
 -9,223,372,036,854,775,808~9,223,372,036,854,775,807

(2)リテラル(直定数)
リテラルを書けるのはデータ型で定義されたもののみ。
整数定数 int=5
実数定数 double=3.14, double=3.0e-10, double=3.14F、
文字定数 char=’A’ ,char=’\n’(改行),char=’\t’(タブ)
文字列定数 char=”Hello\n”,char=”あいうえお”

(3)変数
変数名はデータを記憶するメモリーの場所(アドレス)で変数の名前とデータ型を指定して定義する。データ型で必要なメモリーのバイト数がわかる。
例)int a;

(4)演算子
①算術演算子
 + 加算 a+b aにbを加えた値を戻す
 - 減算 a-b aからbを引いた値を戻す
 * 積算 a*b aとbの積の値を戻す
 / 除算 a/b aをbで割った商を戻す
  a,bが共に整数なら商も整数を戻す。
  aかbが実数なら実数の割り算結果を戻す。
 % 剰余算 a%b

②代入演算子
 = 代入 a=b bの値をaに代入する
 += 加算と代入 a+=b a=a+bと同じ
 -= 減算と代入 a-=b a=a-bと同じ
 *= 積算と代入 a*=b a=a*bと同じ
 /= 除算と代入 a/=b a=a/bと同じ
 %= 剰余算と代入 a%=b a=a%bと同じ

③インクリメント/ディクリメント演算子
 ++ 変数の値を1増加 ++a 増加して値を戻す(前置)
 ++ 変数の値を1増加 a++ 値を戻してから増加する(後置)
 – 変数の値を1減少 –a 減少させてから値を戻す(前置)
 – 変数の値を1減少 a– 値を戻してから減少する(後置)

④ビット演算子
 ~ ビット反転 ~a ビットを反転
 & ビット単位のAND a & b aとbのビット毎のAND
 | ビット単位のOR a | b aとbのビット毎のOR
 ^ ビット単位のXOR a ^ b aとbのビット毎のXOR
 << 上位bit側へのシフト a << n aのビットを上位側にn個シフト
  下位ビットは0を補充
 >> 下位bit側へのシフト a >> n aのビットを下位側にn個シフト             
  符号無しの変数は上位に0を補充(論理シフト)
  符号付の変数は最上位ビットの値を補充(算術シフト)

⑤演算子の優先順位と結合規則
・演算子優先順位
関数呼び出し () > 配列要素 [] > アドレス演算子 & > 単項 + - 
> インクリメント演算子 ++,ディクリメント演算子 –,論理演算の否定 !
> ビットの反転 ~,sizeof演算子,キャスト演算子など
乗算 * > 除算 / > 剰余算 % > 加算 + > 減算 – > ビットシフト << >> > 比較 < > <= >= など
・結合規則
優先順位が同じ演算子が連続しているときの優先順位
左から右:下記以外の2項演算子と条件演算子
a*b/cは(a*b)/cの順番
右から左:代入演算子、単項演算子、条件演算子
a=b=cはa=(b=c)の順番

⑥キャスト演算子
(変換先の型名)変換の対象

⑦自動型変換
演算子(オペレータ)の被演算数(オペランド)の型が演算子の想定に一致しない場合に自動的に型変換が行われる

4.3 制御文

4.3.1 判定
 等価演算子 == 等号   真:1 偽:0
 != 不等号  真:1 偽:0
 関係演算子 >,≧,<,≦ 真:1 偽:0
 論理演算子 
 論理積AND && 真:1 偽:0
 論理和OR || 真:1 偽:0
 否定 NOT ! 真:1 偽:0
 優先順位
(高い順)! , < , <= , > , >= , == , != , && , ||

4.3.2 if文(分岐)
if(条件式1)
{
  文1;
}
else if(条件式2)
{
  文2;
}
else
{
  文3;
}

4.3.3 switch文(分岐)
switch(式){
case 定数式1:
文1;
break;
case 定数式2:
文2;
break;
default:(どのcaseにもあてはまらない場合、defaultは省略可)
文3;
}
※定数式はリテラル、またはリテラル間の簡単な演算式でコンパイル時点で値が定まっている式

4.3.4 while文(繰り返し)
while(条件式){文1; 文2;... }
動作:条件式の値が真(0以外)なら文を実行し再び条件式の判定を行い、偽(0)になるまで繰り返す。
 文が1つしか無いときは、ブロック{}を省略できる。
while(条件式) 文 ;

4.3.5 do while文(繰り返し)
繰り返しの文を実行後に条件判定を行う
do {文1;文2; ...} while(条件式);
文が1つしか無いときは、ブロック{}を省略できる。
do 文 ; while(条件式);

4.3.6 for文(繰り返し)
for(初期設定式;条件式;再設定式) { 文1 ; 文2 ; 文3 }
文が1つしか無いときは、ブロック{}を省略できる。
for(初期設定式 ; 条件式 ; 再設定式) 文;
初期設定式を実行後、条件式の値が真(0以外)なら文を実行する。再設定式を実行後、再び条件式の判定を行う。

4.3.7 breakとcontinue文
(1)break文
Switch, while, for, do-while文から出て、次の文へ処理を移す命令
(2)continue文
whileやdo while文なら次の処理を条件式へ移す命令。for文の場合は再設定式へ移す。
breakが繰り返し文の外へ移す命令であるのに対して、continueは繰り返し文の残りをスキップする命令。

4.4 記憶クラスとスコープ
記憶領域はプログラム( 機械語命令)を記憶するコード領域とデータの記憶に使われるデータ領域があり、データ領域は、さらにメモリーの割り当て方でスタック領域(自動記憶域)、スタティック領域(静的記憶域)、ヒープ領域がある。

(1)スタック領域(自動記憶域)
 関数やブロックの中で変数を定義した変数はその関数やブロック内でのみ有効な局所変数(ローカル変数)。自動変数の有効期間は定義したブロックに入ってから出るまでで、ブロックから出たら再度利用される領域。

(2)スタティック領域(静的記憶域)
記憶クラス指定子staticを付けて定義した局所変数と、関数の外で定義したグローバル変数の記憶で使用される領域。
記憶場所の割り当てが変化しないので、多くの関数から名前で参照でき、データの受け渡しに使える。

(3)ヒープ領域
mallocやfree等の関数を用いてプログラム中でメモリーの確保と解放が行える領域で、ポインターを使うなどして確保したメモリーを利用する。

4.5 関数
(1)外部関数の定義と呼出し
1-3_main.c

#include<stdio.h>
#include<stdlib.h>
#include"1-3_func1.h"
int main(){
 func1();
 return 0;
}

1-3_func1.h

extern void func1(void);

1-3_func1.c

#include<stdio.h>
#include<stdlib.h>
#include"1-3_func1.h"
  void func1(){
  printf("これはグローバル関数です\n");
  }

(2)static変数の初期化は関数を最初に呼び出したときのみ
1-3-6_static.c

/*
  staticの変数は、最初だけ初期化されるため、1,1+1=2,
2+2=4,4+3=7,7+4=11となる
  staticの無い変数は都度初期化されるため、1,2,3,4,5となる
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void func(int i){
  static int value1=1;
  int value2=1;
  value1+=i;
  value2+=i;
  printf("value1=%d \n",value1);
  printf("value2=%d \n",value2);
}
int main(){
  int i;
  for(i=0;i<5;i++){
    func(i);
  }
  return(0);
}

4.6 配列

4.6.1 配列

(1)1次元配列
要素の型 配列名[要素数];
int a[5]={1,2,3,4,5};

(2)2次元配列
要素の型 配列名[行数][列数];
int[2][3]={{1,2,3},{4,5,6}};

(3)文字配列
char 配列名[要素数];
ポインタを使った書き方 char * 配列名;
文字列で初期化する場合は要素数を省ける
 char 配列名[ ]=”文字列”;
※配列の要素数は文字列の終端を示す\0を含むため、文字 コード分+1となる。
char t[2][2][2]={{{‘A’,’B’}{‘1′,’2’}},{{‘C’,’D’}{‘3′,’4’}}};

4.6.2 文字列

(1)strcpy()の使い方
1-4-9_const.c

/*
  strcpy()の使い方
  string.hをインクルードする
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define TEST_STRING "This is test.\n"
int main(void){
  //char *src =TEST_STRING; //下記と同じ *pとp[]は同じ
  char src[]=TEST_STRING;
  char dst[sizeof(TEST_STRING)];
  //char dst[50]="12";//上書きされる
  strcpy(dst,src);
  printf("src:%s",src);
  printf("dst:%s",dst);
  return(0);
}

(2)strcpy()の使い方
test2.c

#include <stdio.h>
#include <string.h>
 
int main(void) {
    char str1[16] = "Hello World!";
    char str2[4];
    
    // 文字列のコピー
    strcpy(str2, str1);
    printf("str2の文字列は: %s\n", str2);
    
    return 0;
}

4.7 ポインタ
(1)オブジェクトのアドレス
double型の変数x(オブジェクトともいう)のアドレスは、アドレス演算子”&”で取り出せる。
double x;
&x;(これはdouble型のポインタ)

(2)ポインタ
ポインタ(オブジェクトを指し示すためのオブジェクトであり、ポインタを入れる変数)の宣言は、
double *pt;(double型オブジェクトへのポインタ型といい、略して、double型へのポインタ型、又はdouble *型という)
 ※ポインタの型は、オブジェクトのデータ型に一致させる必要がある。

(3)ポインタが指すオブジェクトの操作
 ポインタに間接演算子”*”を適用することで、ポインタが示すところのオブジェクトを操作できる。
double x;
double *pt;
pt=&x;
*pt;(xのエイリアス(別名)となる)

#include <stdio.h>

int main(void)
{
	double x=1.23;//初期値
	double *pt;//ポインタ宣言
	pt=&x;//変数xのアドレスをポインタに代入
	printf("代入前のx:%lf\n",x);
	*pt=1.25;//ポインタが示すオブジェクト(xのこと)に値を代入
	printf("代入後のx:%lf\n",x);
}

sample_7.c ポインタを介したオブジェトへの代入と読み出し

(4)ポインタの大きさ
sample_8.c

#include <stdio.h>
#include <limits.h>

int main(void)
{
	printf("1バイトのビット数:%d\n",CHAR_BIT);
	int x=0xF4F3F2F1;//初期値
	int *pt;//ポインタ宣言
	pt=&x;//変数xのアドレスをポインタに代入
	printf("代入前のx:%x\n",x);
	*pt=0xF8F7F6F5;//ポインタが示すオブジェクト(xのこと)に値を代入
	printf("代入後のx:%x\n",x);
	printf("xのアドレス:%p\n",&x);
	printf("xのサイズ:%d\n",(unsigned)sizeof(x));
	printf("ptのアドレス:%p\n",&pt);
	printf("ptのサイズ:%d\n",(unsigned)sizeof(pt));
	printf("ptが示すアドレス:%p\n",pt);
	printf("xのエイリアス*pt:%x\n", *pt);
	
}

4.8 列挙型
(1)enum(列挙型)
定数リストで定義される変数はメンバと言う。デフォルトでは定義されたメンバの順に0(ゼロ)から整数値を付与される。
1-4-7_enum.c

#include<stdio.h>
int main(){
  enum{Black,White,Blue,Red,Green};
  int c1;
  c1=Black;
  printf("%d \n",c1);
  return 0;
}

1-4-7-2_enum.c
最初のメンバに付ける整数値を定義することができる。また途中のメンバから付ける整数値を定義することもできる。

#include<stdio.h>
int main(){
  enum{
    Black=1,
    White,
    Blue,
    Red,
    Green
  };
  int c1;
  c1=White ;// 2
  printf("%d \n",c1);
  return 0;
}

(2)enumの使い方
エラー番号を取得して、case文でエラー番号に対応するエラー内容を表示する
2-2-3_main.c

#include <stdio.h>	
#include <stdlib.h>	
#include "2-2-3_func.h"	
	
int main(){	
  Device_Status num;	
  num=get_device_status();	
  char *name;	
  switch(num){	
  case DEVICE_ERROR:name="エラー";break;	
  case DEVICE_INITIALIZING:name="初期化中";break;	
  case DEVICE_RUNNING:name="動作中";break;	
  case DEVICE_WAITING:name="待機中";break;	
  case DEVICE_DISABLE:name="使用不可";break;	
  }	
  printf("デバイス状態:%s \n",name);	
  return 0;	
}	

2-2-3_func.h

//定数の宣言
typedef enum{
  DEVICE_ERROR = -1,  //エラー
  DEVICE_INITIALIZING,  //初期化中
  DEVICE_RUNNING,  //動作中
  DEVICE_WAITING,  //待機中
  DEVICE_DISABLE  //使用不可
} Device_Status;
//プロトタイプの宣言
Device_Status get_device_status();

typdefにより”Device_Status”が構造体の型名となる

2-2-3_func.c

#include <stdio.h>
#include <stdlib.h>
#include "2-2-3_func.h"
Device_Status get_device_status(){
  Device_Status error_no;
  return(error_no=DEVICE_INITIALIZING);
}

ここでは、enumで定義したエラーを返す。
gcc 2-2-3_main.c 2-2-3_func.h 2-2-3_func.c

4.9 プリプロセッサ
 プリプロセッサはコンパイル前の前処理で文字列の置き換えを行う。プリプロセッサの起動で処理されるものは、#include,#ifdef,#defineなどがある。

(1)#include文
 ソースファイルに別のファイル(ヘッダーファイル)を読みこむという機能で
ファイル名を「<>」でくくる方法と「””」でくくる方法の2つがある。
 「<>」でくくる方法はコンパイラーに環境変数などで設定されたパスから探す。
「””」でくくる方法はカレントディレクトリを探して、無ければコンパイラーに環境変数などで設定されたパスから探す。

(2)#ifdef文,#ifndef文
・インクルードのネストによって多重インクルードの発生を防止する
 #ifndef _FILE_INCLUDED
 #define _FILE_INCLUDED
 (ヘッダファイルの本体)
 #endif /* _FILE_INCLUDED */

 ヘッダファイル名”_FILE_INCLUDED”(名前は任意)が定義されていないときは定義してヘッダファイルを読み込む。また、ヘッダファイル名”_FILE_INCLUDED”が定義されていたときはヘッダファイルは読み込まないで#endifに移る。

・先に定義を有効になる書き方
 #ifndef MAX(x,y)
#define MAX(x,y) ・・・
#endif

・後に定義した方が有効になる書き方
#ifdef MAX(x,y)
#undef MAX(x,y) ・・・
#endif
#define MAX(x,y)・・・

(3)#define文
 文字列の置き換えを行う。
・定数の定義
#define PI 3.14
・マクロの定義
#define MAX(x,y) ((x)>(y) ? (x):(y))
sample_11.c

#define PI 3.14
#define MAX(x,y) ((x)>(y) ? (x):(y))
#include <stdio.h>

int main(void){
    printf("PI:%5.3f\n",PI);
    int x=1;
    int y=2;
    printf("MAX(%d,%d):%d\n",x,y,MAX(x,y));
}

4.10 構造体と共用体

4.10.1 構造体
 複数のデータを格納する箱(変数)をつくるとき、配列は同じ型のデータを複数格納できるが、構造体では異なるデータを複数格納することができる。
(1)構造体の型を作成
struct タグ名
{
 データ型 メンバ名;
 データ型 メンバ名;
 データ型 メンバ名;

};

(2)構造体の宣言
・変数名の構造体を1つ作成するとき。
 struct タグ名 構造体変数名;
・同じ変数名の構造体を複数作成するとき。
 struct タグ名 構造体変数名[要素数];

(3).演算子
 構造体オブジェクト内のメンバは”オブジェクト名.メンバ名”で参照。

(4)構造体の初期化
 各メンバに与える初期化子を{ , ,・・・}の形でコンマで区切って順に並べる。

sample_12.c

#include <stdio.h>

int main(void){
    //構造体の名前(タグ)をmenberとする
    struct member {
        char* name;
        int age;
    };

    //構造体のオブジェクトを定義
    struct member s1={"suzuki",20};//初期化
    struct member s2;

    //構造体のオブジェクトに値をセット
    //s1.name="suzuki";
    //s1.age=20;
    s2.name="satou";
    s2.age=35;

    //構造体のオブジェクトから値を取得
    printf("s1-name:%.10s\n",s1.name);
    printf("s1-age:%d\n",s1.age);
    printf("s2-name:%.10s\n",s2.name);
    printf("s2-age:%d\n",s2.age);

return (0);
}

(5)構造体中の構造体
 構造体のメンバとして、構造体のオブジェクトを持つことができる
sample_13.c

#include <stdio.h>

int main(void){

    struct team {
        char* t_name; 

        struct member{
            char* m_name;
            int age;
        }m1; //teamのメンバとしてオブジェクトを定義する
   }; 
    //構造体teamのオブジェクトを定義
    struct team t1;
    //値の設定
    t1.m1.m_name="suzuki";
    t1.m1.age=20;
    t1.t_name="tokyo";

    //構造体のオブジェクトから値を取得
    printf("t1.m1.name:%.10s\n",t1.m1.m_name);
    printf("t1.m1.age:%d\n",t1.m1.age);
    printf("t1.t_name:%.10s\n",t1.t_name);

return (0);
}

4.10.2 共用体
 構造体が複数のメンバを同時に持つのに対して、共用体は記憶域を共有するため、同時には1つのメンバのみを持つ。

sample_14.c

#include <stdio.h>

int main(void){
    //構造体の名前(タグ)をmenberとする
    union xy {
        int x;
        double y;
    };

    //構造体のオブジェクトを定義
    union xy xy1;
    //構造体のオブジェクトに値をセット
    xy1.x=10;
    //構造体のオブジェクトから値を取得
    printf("xy1.x:%d\n",xy1.x);
    printf("xy1.y:%f\n",xy1.y);
    printf("xy1.xのアドレス:%p\n",&xy1.x);
    printf("xy1.yのアドレス:%p\n",&xy1.y);

return (0);
}

4.11 ファイル入出力
①ファイルを開く
 FILE *fopen(const cahr *fname, const char *mode);
 fopen関数は、ファイルの読み書きに必要な情報を入れるFILE構造体を作成して、そのアドレスをFILE型のポインタとして返す。
 ”r”:読み込み専用でテキストファイルを開く。
 ”w”:書き出し専用で新しいテキストファイルを開く。
 同名 の既存ファイルがある場合ファイルは消されて空のファイルが作られる。
 ”a”:追記専用でテキストファイルを開く。
 同名の既存ファ イルがある場合データは既存ファイルに追記される。
 ”r+”:更新(読み書き可能)用でテキストファイルを開く。
 ”w+”:更新(読み書き可能)用で新しいテキストファイル を開く。
 同名の既存ファイルがある場合ファイルは消されて空のファイルが作られる。

②ファイルを閉じる
 int fclose(FILE *stream);
 fclose関数は、必要でなくなったFILE構造体のメモリーを開放する。
 streamが入力の場合はまだ読まれていないデータを捨て、出力の場合はバッファのデータをフラッシュする。
 streamが指すFILE型領域を解放しファイルを閉じる。正常で0、異常でEOFを戻す。

③ファイルへの書き込み
・指定した文字列をファイルポインタが示すファイルに書き込む
 int fputs(const char * str, FILE * fp);
 引数1:ファイルへ書き込みたい文字列へのポインタ
 引数2:文字列を書き込みたいファイルポインタ
 戻り値:正常書き込み0、書き込み失敗で「EOF(-1)」を返す

④ファイルから読み出し
・ファイルから1文字読み出す
 int fgetc(FILE * fp);
 引数1:文字を読み込みたいファイルポインタ
 戻り値:ファイルから読み込んだ1文字
 ファイルの終端まで読み込んだ場合は「EOF」が戻り値となる。
 読み込み異常時も「EOF」が戻り値となる。

・ファイルから1行分の文字列(改行文字まで)を読み出す
 char * fgets( char *s , int len , FILE *fp );
 第一引数は文字配列のポインタ
 第二引数は一行の最大文字数
 第三引数はファイルポインタ
 戻り値:ファイルポインタfpから1行、またはlenバイト読み込んでその先頭アドレスを返す。
 全行を読み込んだ場合、又はエラー時にNULL(\0)を返す。

(1)ファイル書き込み
sample_5.c

#include <stdio.h>

int main(void)
{
	FILE * fp = NULL;
	fp=fopen("Hello.txt", "w");
	fputs("Hello\n", fp);
	fputs("World\n", fp);
	fclose(fp);
	return 0;
}

Hello.txt

(2)ファイル読み出し
sample_6.c

#include <stdio.h>

int main(void)
{
	char s[15];
	FILE * fp = NULL;
	fp=fopen("Hello.txt", "r");
	if (fp == NULL) {
        	printf("file open errer.\n");
        	return 1;
    	}
	while(fgets(s, 15, fp) != NULL) {
		printf("%s", s);
	}
	fclose(fp);
	return 0;
}

The subject ends herewith.