以前「C++の絵本」を読んだが、ポインタ回りの理解が緩い気がするので念のため「Cの絵本」も読んでみる
0章
auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while
コメント
/* 普通のコメント */ // c++のコメントの書き方(コンパイラがサポートしているので使えてしまう)
1章: 基本
# include <stdio.h> main(){ printf("Hello\n World!\n"); }
printf("%d", 25);
printfの書式指定
意味 | |
---|---|
%d | 整数を10進数で表示 |
%f | 実数 |
%c | 文字('a') |
%s | 文字列("hello") |
%4d | 全体を4桁で |
%04d | 0埋め |
%4.1d | 全体4桁、小数点1桁まで |
コード | エスケープシーケンス | |
---|---|---|
0 | \0 |
NULL |
8 | \b |
BS |
9 | \t |
TAB |
10 | \n |
LF(改行) |
13 | \r |
CR(復帰=行頭に移動して重ね書き) |
\\ |
\ | |
\' or \" |
' or " |
- 数値型
型 | 範囲 | サイズ(ビット数) |
---|---|---|
int | - | - |
unsigned int | - | - |
long | -2147483648~2147483647 | 32 |
unsigned long | 0~4294967295 | 32 |
short | -32768~32767 | 16 |
unsigned short | 0~65555 | 16 |
char | -128~127 | 8 |
unsigned char | 0~255 | 8 |
float | -3.4 x 10^{38}~3.4 x 10^{38} | 32 |
double | -1.7 x 10^{38}~1.7 x 10^{38} | 64 |
- 文字型: 0~127を文字に対応させている
// NULL文字(\0)が最後に入る char t[6] = "hello"; char t = "hello"; char t[6]; strcpy(t, "hello");
2章: 演算子
+
、-
、*
、/
、%
などがある。a++だと変数の参照が演算より優先、++aは演算が変数の参照に優先。
&&
がand、||
がor、!
が否定。
- 条件付き代入
int a = 30, x; /* x == 30 */ x = (0 <= a && a <= 100) ? a : 0;
%x
で16進表示、0x11
で17を表す。
ビットは0/1、バイトは8ビット(違うという話を聞いた気もするが自分には関係なさそうなので無視)。
// short型のバイト数 sizeof(short); // int型のバイト数 int n; sizeof(n);
- 型の変換
演算中は広い方の方に変換される。入りきらないとオーバーフローすることに注意。(型)
で型キャスト。
printf("%f", 3/(float)2) // 1.500000
3章: 制御文
- if
if (a < 10) { } else if (a == 10) { } else { }
- for
for (i = 1; i <= 2; i++)
- while, do~while
while (a < 5) { if () break; // ループを終了 } do { if () continue; // 中断して次のループ処理 } while (a < 5)
- switch(パターンマッチ??)
char s[2] switch(s) { case "a": printf(); case "q": break; default: printf(); }
- goto
if (p == NULL) goto ERROR; . . ERROR: printf("oh no!");
4章: 配列とポインタ
int a[4] = {1, 2, 3, 4}; char s[2] = {'a', '\0'}; int a[][] = {{1,2}, {0,1}};
- 文字列関数
# include <string.h>
して、
char s[4] = "abc"; strlen(s); // 3 strcpy(ss, s); // コピー strcat(ss, s); // 結合 strcmp(s, ss); // 先頭から順に比較 sprintf(s, "%f", 10.1); // 数値→文字列変換(printfの要領で) int n = atoi(s) // 文字列→数値変換 /* 確保の仕方は違うが値は同じ*/ char* s[3]; // ポインタだけ、実態は不連続な領域 s[0] = "this"; s[1] = "bar"; s[2] = "boo"; char s[3][3] = {"this", "bar", "boo"}; // 連続した領域
- アドレス
int a = 1; int* p = &a; int b = *p;
- NULLポインタ
int* p = NULL; if (p == NULL) or if(p) // TRUE if (p != NULL) {} or if(!p)// FALSE
ポインタは演算も出来る。
int a[] = {1, 0}; int* p = a; printf("%d%d", *p+1, *(p+1)) // 20
- メモリの確保
静的なメモリ確保、動的なメモリ確保がある。
// 静的 int a[10][10]; // 動的 # include <stdlib.h> # include <malloc.h> # include <memory.h> int* a; a = (int*)malloc(sizeof(int)*1000); // 1次元、mallocの返り値の型はvoid* free(a); // 多次元は1次元配列のほうが速いし、メモリ効率も良さそう
多次元配列についてはhttp://tondol.hatenablog.jp/entry/20090713/1247426321が分かりやすい。
a = (int*)calloc(sizeof(int)*10); //要素を確保した後全て0にする a = (int*)realloc(int, sizeof(int)*100); // 既に確保したメモリを確保し直す(アドレスは同じとは限らない) memset(a, 0, 5) // aの先頭から5バイトを0にする memcpy(a, src, 5) // aの先頭から5バイトにコピー元の内容を書き込む(srcは先頭アドレス)
main(){ char* b; char a[3] = {10, 20, 30}; b = (char*)malloc(sizeof(char)*10); if(!b) return; // 確保に失敗した場合はmain関数を終了 memcpy(b, a, sizeof(char)*3); }