ポインタとは
- アドレス・・・メモリの場所(変数に&をつけるとわかる)
- ポインタ・・・アドレスを格納する変数
アドレスを出力するときの変換仕様は%pです。
記号 * の使い方
- ポインタの宣言
- 間接参照演算子(ポインタに格納したアドレスの変数 の値を参照できる)
- 乗算演算子(掛け算)
記号 [ ] の使い方
- 配列の宣言
- 添字演算子(アドレスの足し算)
使用例(配列の使い方としてよく忘れます)
int a[5];
例えば、このような整数の配列aを宣言したら、
a や &a[0] は先頭アドレスを表し、
*a や a[0] は先頭の値を表します。
i番目の値は *(a + i) や a[i] と書くことで使えます。
関数使用時の引数と配列・ポインタ
数値の配列の渡し方の例
2つの方法の例としてコードを書いていますが、見てほしいのは3, 6, 13行目だけです(しかも3行目にしか違いはありません)。aは配列なので a が配列の先頭アドレスを表すことに注意してください。つまり、どちらも実引数としてアドレスを渡しています。
1.仮引数が配列
#include <stdio.h>
int sum(int a[]){
int i, sum=0;
for(i=0; i<5; i++){
sum += a[i];
}
return sum;
}
int main(void){
int a[5]={1, 1, 2, 3, 5};
printf("%d\n", sum(a));
return 0;
}
2.仮引数がポインタ
#include <stdio.h>
int sum(int *a){
int i, sum=0;
for(i=0; i<5; i++){
sum += a[i];
}
return sum;
}
int main(void){
int a[5]={1, 1, 2, 3, 5};
printf("%d\n", sum(a));
return 0;
}
この場合、6行目は sum += *(a + i); とも書けます。
この2つの方法の違いは3行目の仮引数のところだけです。
また、どちらも実引数でアドレスを渡しているので参照渡しになっています。
文字列の扱いと渡し方
注意
どうやらC言語での文字列の扱いはかなり難しいようです。面倒なので、ここではほんの少ししか触れていませんm(__)m。競プロ目的であれば、おとなしくC++を使いましょう。C言語で文字列を扱う時は、最後にNULL文字( \0 と書く)が1文字分として入ることを忘れないようにしましょう。今回の文字列とは英語アルファベットを想定しています。
また、string.hをincludeすることで、長さやコピー、連結、比較などの標準ライブラリ関数を使うことができます。
文字列を扱うための2通りの宣言
- 配列:char str[文字数+1] (あるいはchar str[ ]=”文字列”)
- ポインタ:char *str;
出力には変換仕様%sを用いて、先頭アドレスstrを渡します。
あるいは変換仕様%cを用いて、for文で1文字づつ扱います。
#include <stdio.h>
#include <string.h>
int main(void){
char str1[] = "Hello";
char *str2 = "World";
printf("%s %s\n", str1, str2);//Hello World
scanf("%s", str1);//今回の場合は5文字までしか基本は入らない
//(scanfはバッファオーバーフローの危険性があることに注意)
//scanf("%s", str2);はセグメンテーション違反になる
//2通りの出力方法
printf("%s %s\n", str1, str2);
for(int i=0; i<5; i++){
printf("%c %c\n", str1[i], str2[i]);
}
return 0;
}
配列の方法の注意点
- 配列に代入ができない(str1 = “別の文字列”ができない)
- scanf(“%s”, s);として文字列を格納できる
(ただしstr1[100]のように領域を確保して宣言しておく必要がある)
(宣言時にstr[ ]=”文字列”とした場合、あとからscanfを使うと、先に入れた文字列より長い文字列を入力したときにコアダンプになる)
ポインタの方法の注意点
- ポインタの指す場所を変えることで文字列を変更できる
(str2=”別の文字列”ということができる) - scanfによって格納することができない
(セグメンテーション違反(コアダンプ)になる)
文字列の解説がほとんどないけれど、この記事のメインではないから許してください…