はじめに
私は初心者である。この備忘録を参考にされようとしている他の初心者の方は、ここに書かれていることを鵜呑みになさらぬようお願いしたい。何か間違いを見つけた方はコメント欄でご報告頂きたい。
配列
配列は、同じ型の変数が一列に並んだ大きな変数だ。
宣言は以下のように
int a[12];
int
型の変数が12個、メモリ内に並んで作られる。それぞれの変数はa[1]
のようにしてアクセスできる。
一つ一つの変数は配列の要素と呼ぶ。インデックスはゼロから始まる。[]
内の値は添え字という。
毎月の食費を格納し、呼び出せる例文だ。ちゃんと動いた。
#include <stdio.h>
int main(void){
int a[12];
int i;
for (i=0; i<12; i++){
printf("Month %d: ", i+1);
scanf("%d", &a[i]);
}
for (;;){
printf("Month? ");
scanf("%d", &i);
if (i<1 || 12<i)
break;
printf("Month %d: %d\n", i, a[i-1]);
}
return 0;
}
添え字を-1
にしても、最後の配列にある値にアクセスできるといった機能はCにはなさそうだ。勝手に新しい要素に代入みたいなこともできなかった。
printf("%d\n", a[-1]); // 動かん
int a[2];
a[2] = 3; // 動かん
配列の初期化
要素数が初期値より多いとエラーになり、少ないと残りの要素がゼロになる。
#include <stdio.h>
int main(void){
int days[12] = {31,28};
for (int i=0; i<12; i++)
printf("%d\n", days[i]);
return 0;
} // 31と28が出力された後は0が10個
下記のような初期化もできる。
int days[] = {31,28}; // 自動で要素数が2になる
あくまで初期化のみであって下記のような代入はエラーが出る
int days[];
days = {31,28}; // エラーになる
初期化の応用
int
型の要素を1000個もつ配列a
を宣言し、要素を全てゼロで初期化するなら以下のようにかける。
int a[1000] = {0};
printf("%d\n", a[500]); // 出力は0
もしこれが、外部変数やstatic
変数ならば明示的に初期化しなければ、すべての要素がゼロになる。
static int a[1000];
printf("%d\n", a[500]); // 出力は0
多次元配列の基本
まぁ想像がつくから、はしょる。
P391
(苦しんで覚えるC言語参照)
要素数を求める
これは面白いな。
配列全体のサイズを求め、それを要素1つのサイズで割れば要素の数がわかる。
static int a[1000];
int len;
len = sizeof(a) / sizeof(a[0]);
printf("%d\n", len); // 出力は1000
memcpy関数
配列をコピーするための関数だ。
memcpy(コピー先配列名、コピー元配列名、配列全体のサイズ)
の形の関数だ。
memory.h
ファイルを#include
して使う。
#include <memory.h>
#include <stdio.h>
int main(void)
{
int array1[] = { 42, 79, 13, 19, 41 };
int array2[] = { 1, 2, 3, 4, 5 };
int i;
for (i = 0; i < sizeof(array2) / sizeof(array2[0]); i++) {
printf("array2[%d] = %d\n", i, array2[i]);
}
memcpy(array2, array1, sizeof(array1)); /* array1 の全要素を array2 にコピー */
for (i = 0; i < sizeof(array2) / sizeof(array2[0]); i++) {
printf("array2[%d] = %d\n", i, array2[i]);
}
return 0;
}
関数の戻り値はなく?(あるそうだ)これだけでコピーが完了する。
この関数はコピー元の配列がコピー先のものより長かったとしても、無理やりコピーして
バッファオーバーランとかいうタチの悪いエラーを引き起こすらしいから注意しよう。
文字を扱う
文字変数としてchar
型がある。
printf
関数で表示するには%c
指定子を使う。
#include <stdio.h>
int main(void){
char c = 'A';
printf("%c\n", c); // 出力はA
return 0;
}
文字はUnicodeがベースになってるから下記のコードでも出力はA
コメント参照 環境によるそうだ
#include <stdio.h>
int main(void){
char c = 65;
printf("%c\n", c);
return 0;
}
下記のコードの出力はJ
#include <stdio.h>
int main(void){
char c = 'A' + 9;
printf("%c\n", c);
return 0;
}
文字列を扱う
Cでは文字変数の配列を使うことで文字列になるらしい。
文字列の最後にはEOS(End of String)を置いて文字列の終わりを表す。
文字列の指定子は%s
#include <stdio.h>
int main(void){
// char str[6] = {"M", "A", "R", "I", "O", "/0"}; // ダブルクオーテーションは動かないから注意
char str[6] = {'M', 'A', 'R', 'I', 'O', '\0'};
printf("%s\n", str);
return 0;
}
なお、配列の初期化の時に要素の省略をした場合は、法則に従い、残りにはゼロが格納される。
文字列の初期化
C言語にはもっと簡単に文字列を初期化できる方法がある。
それが文字列リテラル。
文字を一つ一つ区切らずに、ダブルクオーテーション""
で囲うことで初期化に使える。
以下が例だ。
#include <stdio.h>
int main(void){
char str[] = "MARIO";
printf("%s\n", str);
return 0;
} // MARIOと出力される
初期化の時しかまとめて代入できず、その後は一文字ずつ代入しなければならないのは変わらない。
文字列を扱う関数
文字列の入力
文字列を入力するときは以下のようにする。
#include <stdio.h>
int main(void){
char str[32];
scanf("%s", str); // 注目
printf("%s\n", str);
return 0;
}
scanf
関数のときに&
がない。&
を使わないのはポインタと深く関わりがあるらしい。次章で扱うから今は保留。
追記 下記のコード
文字列は初期化の時しかまとめて代入できないと書いたが、下記のコードのようにインプットがある場合は一度に入るようだ。
#include <stdio.h>
int main(void){
char str[3];
scanf("%s", str);
printf("%s\n", str);
return 0;
}
memcpy
関数のところで書いたような、配列の大きさを超えて代入されるようなことを防ぐには下記のようなコードが使える。
#include <stdio.h>
int main(void){
char str[32];
scanf("%32s", str); // 32文字を超えると切り捨てられる。
printf("%s\n", str);
return 0;
}
ここに載せた以外の関数も先ほど示したリンクに記載されている。
今回の内容は富永和人氏の新しいC言語の教科書を参考に書き留めてます。