blog/content/post/2008/05/02/2008-05-02-『新版c言語プログラミングレッス...

13 KiB
Raw Blame History

title author date wordtwit_post_info categories
『新版C言語プログラミングレッスン 入門編』第11章・ポインタ kazu634 2008-05-02
O:8:"stdClass":13:{s:6:"manual";b:0;s:11:"tweet_times";i:1;s:5:"delay";i:0;s:7:"enabled";i:1;s:10:"separation";s:2:"60";s:7:"version";s:3:"3.7";s:14:"tweet_template";b:0;s:6:"status";i:2;s:6:"result";a:0:{}s:13:"tweet_counter";i:2;s:13:"tweet_log_ids";a:1:{i:0;i:3971;}s:9:"hash_tags";a:0:{}s:8:"accounts";a:1:{i:0;s:7:"kazu634";}}
C
Programming

 難関に入ります。

「ポインタ」とは何か?

「ポインタとは、変数のアドレスをもつ変数である」

http://www.amazon.co.jp/%E6%96%B0%E7%89%88C%E8%A8%80%E8%AA%9E%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%83%AC%E3%83%83%E3%82%B9%E3%83%B3-%E5%85%A5%E9%96%80%E7%B7%A8-%E7%B5%90%E5%9F%8E%E6%B5%A9/dp/4797336781/ref=sr_1_10?ie=UTF8&s=books&qid=1209639049&sr=1-10:title

とりあえず研修でハードウェアについてたたき込まれているので、この説明でなんとなくわかる。要は主記憶上のアドレスを格納できる変数を「ポインタ」という…みたいです。

「ポインタ」の定義の仕方

 こんな感じだよー。

int *p;

「ポインタ」への代入

 「&」演算子を用いると変数のアドレスがわかります。例:

p = &x;

「ポインタ」の参照

 printfではこんな感じになる。

printf("%p\n", p);

また、ポインタが指している他の変数の値も参照できる。例えば

int x;
int *p;
x = 123;
p = &x;
*p = 456;

とすると、xの値が456になる。

「ポインタ」のインクリメントとか

  • 「p++」: ポインタpが「一つ次」の変数を指すようになる
  • 「p」: ポインタpが「一つ前」の変数を指すようになる

http://www.amazon.co.jp/%E6%96%B0%E7%89%88C%E8%A8%80%E8%AA%9E%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%83%AC%E3%83%83%E3%82%B9%E3%83%B3-%E5%85%A5%E9%96%80%E7%B7%A8-%E7%B5%90%E5%9F%8E%E6%B5%A9/dp/4797336781/ref=sr_1_10?ie=UTF8&s=books&qid=1209639049&sr=1-10:title

#include <stdio.h>
void swap_int(int *xp, int *yp);
int main(void);
void swap_int(int *xp, int *yp)
{
int tmp;
tmp = *xp;
*xp = *yp;
*yp = tmp;
}
int main(void)
{
int x, y;
x = 4;
y = 5;
printf ("x = %d, y = %d\n", x, y);
swap_int(&x, &y);
printf ("x = %d, y = %d\n", x, y);
}

ここで個人的に注意すべきなのは、void swap_intのところでの「*xp」などといった表記は、「変数がポインタである」ことを示す。それに対して、以降の「*xp」などは「xpに入っているアドレスが参照している変数」を指す。この違いが分からず、ちょっと混乱してしまった。

配列とポインタの関係

 ポインタのインクリメントは、おそらく配列の内部で使うことを想定しているのだと思われる。

#include <stdio.h>
int main(void);
int main(void)
{
int x[3] = {1, 3, 9};
int *p_x;
int i;
p_x = &x[];
for (i = ;i < 3;i++) {
*p_x = *p_x * *p_x;
p_x++;
}
for (i = ;i < 3;i++) {
printf ("x[%d]: %d\n", i, x[i]);
}
return();
}

これは

#include <stdio.h>
int main(void);
int main(void)
{
int x[3] = {1, 3, 9};
int i;
for (i = ;i < 3;i++) {
x[i] = x[i] * x[i];
}
for (i = ;i < 3;i++) {
printf ("x[%d]: %d\n", i, x[i]);
}
return();
}

と結局同じことをしていることになる*1

構造体と「ポインタ」の関係

#include <stdio.h>
#include <string.h>
int main(void);
struct student
{
int id;
char name[20];
int japanese;
int math;
int eng;
};
int main(void)
{
struct student yukari;
struct student *p;
yukari.id = 1;
strcpy(&yukari.name[], "Yukari");
yukari.japanese = 80;
yukari.math = 70;
yukari.eng = 100;
p =
/* 構造体のポインタを用いた参照はこのように書く */
(*p).id = 2;
printf ("Yukari's id: %d\n", (*p).id);
/* もしくはこのように書く */
p->id = 3;
printf ("Yukari's id: %d\n", p->id);
return();
}

練習問題

 一つ目の変数の阿智が二つ目より小さいときには値を交換し、そうでないときには何もしない関数をポインタを用いて作るよ。

#include <stdio.h>
void swap_bigint(int *x, int *y);
int main(void);
void swap_bigint(int *x, int *y)
{
int tmp;
if (*x < *y) {
tmp = *x;
*x = *y;
*y = tmp;
}
}
int main(void)
{
int x, y;
x = 5;
y = 3;
printf ("Setting Value: x -> %d, y -> %d\n", x, y);
swap_bigint(&x, &y);
printf ("After the swap_value: x -> %d, y -> %d\n", x, y);
return();
}

*1でも、私には二つ書き方があることは分かっても、二つの違いは分からなかったりorz。たぶん、効率とかなんかが違うのだと思われる