C言語(二)ポインタ


一、ポインタの概要
1.概要
ポインタ:実は住所です.
ポインタ変数:変数アドレスを格納する変数.
2.初期化
1)定義後初期化
int a =10;
int  *p;
p=&a;
2)定義と初期化
int a=10;
int *p =&a;
注記:データ型の後、変数名の前にある「*」は、ポインタ変数であることを示す説明子です.
*pのようなデータ型が前にない場合、ここでは「*」はポインタ変数が指す変数を取り出すポインタ演算子です.
3.ポインタ変数の使用メモリ
同じコンパイラ環境では、ポインタ変数のタイプに関係なく、使用されるメモリは固定されます.
コンパイラによって、ポインタ変数の使用メモリが異なります.
16ビット・コンパイラ->2バイト、32ビット・コンパイラ->4バイト、64ビット・コンパイラ->8バイト
二、ポインタと配列
1.pはポインタ、aは配列
1)pが配列要素を指す場合、p+1は常に配列要素を指す次の要素を表す.コンパイラ環境に関係なく、指向するデータ型に関係ありません.
例えば、p=&a[2]、p+1=&a[3]
2)異なるタイプの配列要素では,p値の変化は異なる.配列要素がint型の場合、p+1はpの値に2(16ビットコンパイラ環境)を加え、p+1の値がいくらであっても、常に次の要素を指すことを保証します.
2.pの初期値が&a[0]であると仮定すると、
1)p+iとa+iは,いずれも要素a[i]のアドレスを表すことができる.これらは、配列のi番目の要素のアドレスを指します.
2)*(p+i)と*(a+i)は、いずれも配列要素a[i]を表す.
3)p+iとa+iはいずれも配列のi番目の要素を指すが,両者には違いがある.ポインタ変数としてのpは、p++のように自身を変えることができる値である.しかし、aは配列のヘッダアドレスを表す定数であり、配列の名前でもあり、その値は変更できません.すなわち、a++は合法ではありません.
3.配列名を関数実パラメータとする場合、実際には配列のヘッダアドレスをパラメータ配列に渡し、2つの配列は同じメモリ空間を共通にする.
4.多くの場合、ポインタと配列は互いに切り替えて使用できるが、ポインタが配列であるとは言えない.
5.例
#include <stdio.h>
#include <string.h>
int main() {
	//     int     
	int a[4] = {1, 2, 3, 4};
	//     int     ,       0   
	int *p = a;
	int i;
	for (i = 0; i < 4; i++) {
	    //        *        
	    int value = *(p+i);
	    printf("a[%d] = %d 
", i, value); } return 0; }

三、ポインタと文字列
1.文字列は特殊な文字配列と見なすことができ、自然に配列である.特殊なのは、配列の末尾に「0」が自動的に追加され、末尾を表すためです.
2.ポインタと文字列の使用
#include <stdio.h>
int main() {
	char a[10]="china";
	char b[10];
	//b="china";	//  b       ,     ,        
      
	char *c="china";
	char *d;
	d="china";//   ,    
	char *e="china";//e       ,        china
	e="uk";	//    uk,        
	//*e='m';//  e        ,      
	int leng =strlen(e);
	printf("%d
",leng); // :2 printf("%c
",*e); // e 。 //printf("%s
",*e); // e uk “u”, 。 return 0; }

3.遍歴文字列
	char a[]="china";
	char *p=a;
	for(;*p !='\0';p++){
		printf("%c",*p);
	}
//    :china

四、ポインタと関数
1.振り返る
    int *p=12;
pはアドレスを格納する.
*pはメモリアドレスを取り出す値です.
p+1,次のアドレス
*(p+1)、次のアドレスの値
2.ポインタを返す関数
char * upper(char *str) {
    //         。    str           。
    char *dest = str;
    //         
    while (*str != '\0') {
        //        
        if (*str >= 'a' && *str <= 'z') {
            //       。        ASCII        
            *str -= 'a' - 'A';	//a-97 A-65
        }
        //        
        str++;	//     
    }
    //      
    return dest;
}

3.関数へのポインタ
ポインタが関数を指すのはなぜですか?
関数はプログラムとして、メモリにも一部の記憶空間を占有し、関数のエントリアドレスである開始アドレスもあります.関数にアドレスがある以上、ポインタ変数はアドレスを格納するために使用されるので、ポインタは関数を指すことができ、関数名は関数のアドレスである.
4.例
1)宣言と初期化
#include <string.h>
#include <stdio.h>
int sum(int a, int b) {
	return a + b;
}
int main() {
	//int (*p)()=sum;//        
	int (*p)(int, int)=sum;//      
	//int (*p)(int number1,int number2)=sum;
	//int result = (*p)(1, 3);//       
	int result=p(1,3);
	printf("%d
", result); return 0; }

2)実用化
#include <string.h>
#include <stdio.h>
#include <stdio.h>
//     
int minus(int a, int b) {
	return a - b;
}
//     
int sum(int a, int b) {
	return a + b;
}
//    
int mul(int a, int b) {
	return a * b;
}
//   counting      a b     ,           ,     1     
void counting(int (*p)(int, int), int a, int b) {
	int result = p(a, b);
	printf("     :%d
", result); } int main() { // counting(sum, 6, 4);// p // counting(minus, 6, 4); // counting(mul, 6, 4); return 0; }