ばとらの部屋
プログラミング演習I
作成日 2023年12月5日 / 最終更新日 2024年3月3日
同名の変数が存在する場合、呼び出し箇所と近い方の変数が優先される。 グローバル変数は代入せずに宣言すると0を格納する。
#include <stdio.h>
int a;
int main(void){
printf("%d\n",a); // 0
return 0;
}
%[フラグ][最小フィールド幅][.精度][修飾子]変換指定子
変換指定子 | 変数の型 | 概要 |
---|---|---|
%c | char | 文字 |
%s | har * | 文字列 |
%d | int | 10進整数 |
%hd | short int | 半分の精度の10進整数 |
%ld | long int | 倍精度の10進整数 |
%u | unsigned int | 符号なし10進整数 |
%hu | unsigned short int | 符号なし半分の精度の10進整数 |
%lu | unsigned long int | 符号なし倍精度の10進整数 |
%o | int | 8進整数 |
%x | int | 16進整数 |
%f | float | 実数 |
%lf | double | 倍精度の実数 |
%e | float | 実数の指数表示 |
%g | float | 実数の最適表示 |
printf("%f" , 3.14); // 3.140000(デフォルト)
printf("%.2f", 3.14); // 3.14 (下二桁)
printf("%.0f", 3.14); // 3 (小数点以下切り捨て)
printf("%.f" , 3.14); // 3 (小数点以下切り捨て)
printf("%5.2f", 3.14); // " 3.14"(右詰め)(空白が追加される)
printf("%.2f", 0.0 / 0); // "nan" (NaN)
printf("%.2f", 1.0 / 0); // "inf" (Infinity)
前置演算は「先に演算してから代入」
int i = 10;
int j = ++i; //i = 11 j = 11;
後置演算は「先に代入してから演算」
int i = 10;
int j = i++; //i = 11 j = 10;
値渡し | ポインタ渡し | 参照渡し |
---|---|---|
var | *var | &var |
#include <stdio.h>
void add1(int x) {
x += 1;
}
int main(void){
int a = 0;
add1(a);
printf("%d\n", a); // 0
return 0;
}
#include <stdio.h>
void add1(int *x) {
*x += 1;
}
int main(void){
int a = 0;
add1(&a);
printf("%d\n", a); // 1
return 0;
}
変数の前に&
をつけるとその変数のアドレスを取得する。
char x = 'A';
printf("%p\n", &x); // xのアドレスを表示
printf("%c\n", &x); // A
char *p;
p = &x; // ポインタpにxのアドレスを代入
printf("%p\n", p); // アドレスを表示
ポインタに間接演算子*
をつけるとアドレスに格納された値を取得する。
char x = 'A';
char *p;
p = &x; // ポインタpにxのアドレスを代入
printf("%c\n", *p); // A
以下のようにポインタの指す値の変更をすることができる。ただし、ポインタで変数を指していない場合はセグフォになる。
char x = 'A'; // メモリに値を格納
char *p = &x; // pにxのアドレスを代入
*p = 'B'; // pのアドレスの値を'B'に変更
printf("%c\n", *p); // pのアドレスの値を表示
このように間接演算子*
を使うことでポインタに格納されたアドレスのデータにアクセスできる。
ポインタで配列を指すと、配列の先頭を指す。
char arr[] = {'A', 'B', 'C', 'D', 'E'};
char *p;
p = arr;
printf("%c\n", *p); // A
次のように書いても同義で、先頭を指す。
p = &(arr[0]);
ポインタが配列を指しているとき、インデックスを指定して各要素にアクセスすることができる。
char arr[] = {'A', 'B', 'C', 'D', 'E'};
char *p;
p = arr;
printf("%c\n",*p); // A
p[0] = 'F'; // AをFに書き換え
p[3] = 'G'; // DをGに書き換え
このときp = 0
で*p
は配列の0番目にアクセスしている。
p
がarr[1]
を指しているため、p
は1番目を配列の先頭としてみなす。
char arr[] = {'A', 'B', 'C', 'D', 'E'};
char *p;
p = &(arr[1]);
// 以下は基準を配列の1番目とする
p[0] = 'F'; // BをFに書き換え
p[3] = 'G'; // EをGに書き換え
アドレスそのものを加減算で変化させることで、配列の各要素にアクセスすることもできる。
char arr[] = {'A', 'B', 'C', 'D', 'E'};
char *p;
p = arr;
*(p + 3) = 'H'; // CをHに書き換え
*
をつけることでそのアドレスに格納している値にアクセスしていることがわかる。
#include <stdio.h>
int main(void){
int data[]={8,3,2,9,6,7,1,5,4};
int *ip, *iq;
ip = data; // ip = 0, ポインタに配列の先頭アドレスを代入
printf("%d\n", *ip + data[1]); // 8 + 3 = 11
iq = ip+3; // iq = 3, iqは配列の先頭+3番目のアドレスを代入
ip++; // ポインタに配列の先頭+1番目のアドレスを代入
printf("%d\n", *ip + *iq); // 9 + 3 = 12
ip = data; // ip = 0, ポインタは配列の先頭アドレスを指す
printf("%d\n", *(ip + 6)); // 先頭+6番目のアドレスを指す // 1
ip = data + 4; // ポインタは配列の先頭+4番目のアドレスを代入
iq = ip - 3; // iqは配列のip(先頭+4番目)-3番目のアドレスを指す
// iq + data[*ip] = *(1 + data[6]) = *(1 + 1) = 2
printf("%d\n", *(iq + data[*ip])); // 2
return 0;
}
宣言方法
#include <stdio.h>
struct data {
int x;
char str[7];
};
int main(void) {
struct data d = {0, "Hello!"};
d.x = 5; // 構造体dのメンバxに5を格納
printf("%d\n",d.x); // 5
printf("%s\n",d.str); // Hello!
}
アロー演算子->
は、*
と.
をひとつにまとめた演算子である。
ポインタから構造体のメンバへアクセスする演算子である。
struct data d1, d2;
struct data *p = &d1; // ポインタpを宣言して構造体d1のアドレスを代入
(*p).x = 10; // ポインタを使ってd1.xに10を代入
p->y = 20; // アロー演算子を使うパターン
p = &d2; // ポインタpは構造体d2を指す
(*p).x = 30; // d2.x = 30;
p->y = 40; // d2.y = 40;
(*構造体ポインタ).(メンバ名)
を構造体ポインタ->メンバ名
と書くことができる。
switch文においてcaseブロックにbreak文にない場合は次のcaseブロックに進む。
#include <stdio.h>
int main(void){
int k = 0; int i = 0;
switch (k){
case 0: i++; //break;がないので次のcaseに進む
case 1: i = 5; break; //break;があるのでswitch文を抜ける
case 2: i = 10; break;
default: i = 100;
}
printf("i=%d\n", i); // 5
}
C言語において文字列を扱う場合はchar
を使う。char型の変数のサイズは1バイトであり、1変数に1文字しか保存できない。
複数の文字を扱う場合はchar型の配列を使う。基本的にchar型の配列の最後の文字に終端文字(ヌル文字)を入れる必要がある。''
で囲むとヌル文字\0
が必要で、""
で囲むと必要ない。
#include <stdio.h>
int main(void) {
char str1[] = "ABC"; // ""で囲むと文字列型で終端文字が自動で付加される
char str2[] = {'D', 'E', 'F', '\0'}; // ''で囲むと文字型で終端文字が必要
printf("str1 = %s\n", str1);
printf("str2 = %s\n", str2);
return 0;
}
要素数
= 配列全体のメモリサイズ / 配列の要素1つのメモリサイズ
printf("%d\n",1 << 3); // 左シフト 1*2^3
printf("%d\n",5 >> 1); // 右シフト 5/2^1(切り捨て)
printf("%d\n",5 & 3); // AND演算 0101 & 0011 = 0001 = 1
printf("%d\n",5 | 3); // OR演算 0101 | 0011 = 0111 = 7
printf("%d\n",5 ^ 3); // XOR演算 0101 ^ 0011 = 0110 = 6
printf("%d\n",~5); // NOT演算 ~0101 = 1010 = -6