tak0kadaの何でもノート

発声練習、生存確認用。

医学関連は 医学ノート

「Cの絵本」第1章~第4章を読んだ

以前「C++の絵本」を読んだが、ポインタ回りの理解が緩い気がするので念のため「Cの絵本」も読んでみる

「C++の絵本」を読んだ - (1章〜5章)

「C++の絵本」を読んだ - (6章〜9章)

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);
}