経緯
5年ほど前からPythonをちょくちょくいじってはいたが、実務経験がなく、他のスキルを身につけようと昨日(2024/9/17)からCの勉強を開始。忘れそうな点、つまずいた点等をアウトプットしておく。
教材
1. 型
型が何個かあるのは知っており、身構えていたが、動画を見る限りとりあえず使う型はint, double, charの3種類。とりあえず最初はメモリについて気にすることはなさそう?
型 | 意味 |
---|---|
int | 整数 |
double | 小数 |
char | 1文字 |
2. int main(void)
プログラムを実行すると、main関数が実行される。
intは返り値の型、voidは特にないということを意味する。
int main(void){
printf("hello, world\n")
return 0;
}
void系は4種類ある。
// no return, no argument
void hoge(void) {}
// yes return, no argument
int hoge(void) {return 0;}
//no return, yes argument
void hoge(int fuga) {}
// yes return, yes argument
int hoge(int fuga) {return 0;}
3. コンパイル&実行 を同時に
helloWorld.cの実行
% gcc -o helloWorld helloWorld.c && ./helloWorld
4. 変換指定子
%fと%lfの違いがいまいち分からなかった。とりあえずはprintfの時は"%f"、scanfの時は"%lf"と覚えることとする。
変換指定子 | 意味 |
---|---|
%d | 整数 |
%f | 小数 |
%s | 文字列 |
5. n乗
pythonでは"**"で簡単にできていたn乗がCではライブラリの読み込みが必要であった。
参考URL:https://chmod774.com/pow-clang/
ここでなぜ%lfが使われているのかが分からなくて困惑している。
include <math.h>
//3の2乗
pow(3, 2)
6. キャスト変換 int->double, double->int
#include <stdio.h>
int main(void) {
double pie = 3.14;
int five = 5;
printf("%d\n", (int) pie); //3
printf("%f\n", (double) five); //5.000000
}
7 配列の長さ sizeof
sizeof()は、配列の要素数を取得してくれるのかと思い下記を試した。
int array_len = sizeof(array);
これをfor文にぶち込んでみたらバグが発生。
調べてみると、sizeofはarray要素数を取得するのではなく、メモリサイズをバイト数で返す関数のようだ。
(参考URL:https://www.sejuku.net/blog/24793)
つまり、それを要素ひとつ分のメモリサイズで割ると要素数を取得できるという仕組み。
例外はその配列が文字列の場合、型charが使われており、charは1バイトで固定のため、わざわざ1要素のメモリバイトで割る理由がない点だと考えられる。
int array_len = sizeof(array) / sizeof(array[0]);
int words_len = sizeof(words_array);
このことから、配列は、要素ひとつ一つにメモリサイズの違いがないことがわかる(これを理解して役に立つのかは知らない)。
8. 文字列関連
8.1 atoi() str->int
文字列の数字をint型に変換する。
include <stdlib.h>
char str = "123";
int num = atoi(str);
他にも変換先がいくつかある。
関数 | 変換後 |
---|---|
atoi | int |
atod | double |
atof | float |
atol | long |
8.2 文字列連結 strcat()
include <string.h>
char str1[15] = "Hello"; //こっちに結合される
char str2[] = "World";
strcat(str1, str2);
printf("%s\n", str1); //HelloWorld
8.3 文字列数 strlen()
文字列の長さを取得
include <string.h>
char word[] = "hello";
int word_len = strlen(word);
9. ポインタ関連
9.1 ポインタ宣言、住所
#include <stdio.h>
int main(void) {
int num = 100;
int *n; //ポインタ変数宣言
n = # //numのアドレスをnへ代入
*n = 200; //numの要素を変更
printf("%d\n", num); //200
printf("%d\n", *n); //200
}
- &(変数)でその変数の住所
- *(変数)はその変数の要素
を示している。
9.2 複数の戻り値を取得できる
やや苦戦。
#include <stdio.h>
void culc(int x, int *a, int *b, int *c);
int main(void) {
int num = 10;
int num_2;
int num_3;
int num_4;
culc(num, &num_2, &num_3, &num_4);
printf("%d\n", num_2);
printf("%d\n", num_3);
printf("%d\n", num_4);
return 0;
}
void culc(int x, int *a, int *b, int *c) {
*a = x * 2;
*b = x * 3;
*c = x * 4;
}
実行時に引数でそれぞれの変数の住所を渡すことはわかった。しかし、求められているものは変数の要素なのではないか。
-> おそらく、要素としての"*"ではなく、ポインタ変数宣言としての"*"なのではないかと予想する。
9.3 構造体でのポインタ
#include <stdio.h>
struct goods {
char product[20];
int price;
};
int main(void) {
struct goods A = {"shoes", 300};
struct goods *B;
B = &A;
*B.price = 250; //式には構造体または共用体型を使用する必要がありますが、型 "struct goods *" が使用されていますC/C++(154)
printf("%d", *B.price); //式には構造体または共用体型を使用する必要がありますが、型 "struct goods *" が使用されていますC/C++(154)
return 0;
}
構造体でポインタを試してみるとエラーが出る。調べるとクリーンヒットするような記事を見つけた
参考URL:https://daeudaeu.com/arrow/
構造体に使うポインタは
*B.price = 250;
ではなく、
(*B).price = 250;
または、
B->price = 250;
を使うそうだ(おそらく矢印の方が一般的)。正直今の自分には理屈が理解しきれていない。今後理解でき次第、追記しようと思う。