学习C prime plus
指针的基本用法和一些需要清楚的概念(1)
1.指针变量的声明和初始化
指针就是把内存地址做为其值的变量。
(1)指针是一个变量
(2)普通变量直接引用了一个值
如:
int a = 3;
那么a的值就是3。
(3)指针变量只存放内存地址
(4)指针存放的内存地址往往存放有实际的值,但也可能是另外一个指针
如:
int a = 3;
int * aptr = &a;//把a的地址通过取地址运算符赋给指针变量 aptr
printf ("%p", aptr);//打印出指针的值,用16进制的方式
printf ("%p", &a);//打印出a的地址,用16进制的方式
(5)指针变量名间接应用了一个值,我们使用间接引用运算符来取得具体的值
printf (”%d”, *aptr);
(6)指针必须初始化,可以把指针初始化为NULL
NULL在中定义,它的值是0
使用NULL使程序具有可读性。
注意:
& 取地址运算符 取得任何变量的地址
如:
int a;
int *aptr;
int c[5];
//使用&运算符取得地址,并打印出来
printf ("%p\n", &a);//取得整型变量a的内存地址
printf ("%p\n", &aptr);//取得指针变量aptr的内存地址
printf ("%p\n", &c[0]);//取得数组第一个元素的内存地址
* 比较让大家迷惑的是它在这里有两种不同的用法,但实际上它们并不是同样的
(1)和具体的数据类型一起构成对应的指针类型
*在声明语句表示变量是一个指针
int *
float *
char *
double *
(2)间接引用运算符
int a = 3;
int * aptr = &a;//把a的地址通过取地址运算符赋给指针变量 aptr
printf ("%d", *aptr);//通过a的地址间接引用变量a的值
思考:
仔细分析下面的语句的结果。
int a = 8;
int * aPtr;
aPtr = &a;
printf ("%p\n", & * aPtr);
printf ("%p\n", * & aPtr);
提示,一层层分析,可以看做 &(*aPtr)
答案在最下面。
二、指针的传引用调用
1.C语言中所有的函数都是传值调用
为什么,难道指针不是传引用调用吗?
不是,C语言只是把指针的值拷贝一份,传如函数内部。
2.那么传递数组呢?
void printArray (int *nPtr);
和
void printArray (int array[]);
的效果都是一样的,都是传一个地址进去。
另外,要注意:
数组名本身就是地址。
3.指针的传引用调用我们也可称之为模拟传引用调用,因为我们传的是一个地址,
函数调用时,函数的参数会拷贝这个地址,然后通过复引用来操作变量。
int cubeByReference (int * nPtr)//计算立方
{
*nptr = *nptr * *nptr * *nptr;
}
注意这里,
(1)*(复引用运算符)比*(乘法运算符)优先级要高。
所以可以不适用括号,但是推荐你使用下面的语句,这样程序更加清晰。
(2)nPtr是占用堆栈的,函数cubeByReference会给nPtr这个指针变量分配空间,
然后把传入的指针变量的值赋给它。
int cubeByReference (int * nPtr)//计算立方
{
(*nptr) = (*nptr) * (*nptr) * (*nptr);
}
4.传值为什么不改变传入变量的值
因为它是在堆栈中生成一个新的变量,然后把存放的值拷贝过来,最后函数结束的时候把该变量从堆栈中释
放掉,所以并不会改变传入变量的值。
就像你用一张新的纸把一张纸上的东西复制一遍,然后在新的纸上写写画画,然后丢掉,并不会影响到原来
的纸上的内容。
5.传指针(也就是传引用为什么会改变)
因为指针给出了原来变量的地址,使得*(复引用指针)可以通过这个地址找到这个变量并对它进行修改。
三、指针的const限定
(1)指向非常量数据的非常量指针
int a;
int b;
int *aPtr;
aPtr = &a;//OK
aPtr = &b;//OK
*aptr = 3;//OK
(2)指向常量数据的非常量指针(不能修改指向变量中的数据)
const int * aPtr;
注意:const 修饰int
int a;
int b;
const int *aPtr;
aPtr = &a;//OK
aPtr = &b;//OK
*aptr = 3;//ERROR 不能修改指向的变量中的数据
(3)指向非常量数据的常量指针(不能东指西指)
int * const aPtr;
注意: const 修饰指针变量 aptr;
数组名是一个很好的例子。(参见字符串数组中的说明。)
int a;
int b;
const int *aPtr = &a;
aPtr = &b;//ERROR 不能再指向另外一个变量
*aptr = 3;//OK
(4)指向常量数据的常量指针(不能修改指向变量中的数据,不能东指西指)
const int * const aPtr;
int a;
int b;
const int * const aPtr = &a;
aPtr = &b;//ERROR 不能再指向另外一个变量
*aptr = 3;//ERROR 不能修改指向的变量中的数据
答案:
1.实际上*aPtr相当于a, &*aPtr就取得a的地址
2.&aPtr取得aPtr的直至,而*&aPtr就取得aPtr存放的值,也就是a的地址
3.&*会相互抵消,实际上&*aPtr == aPtr == *&aPtr
指针的基本用法和一些需要清楚的概念(1)
1.指针变量的声明和初始化
指针就是把内存地址做为其值的变量。
(1)指针是一个变量
(2)普通变量直接引用了一个值
如:
int a = 3;
那么a的值就是3。
(3)指针变量只存放内存地址
(4)指针存放的内存地址往往存放有实际的值,但也可能是另外一个指针
如:
int a = 3;
int * aptr = &a;//把a的地址通过取地址运算符赋给指针变量 aptr
printf ("%p", aptr);//打印出指针的值,用16进制的方式
printf ("%p", &a);//打印出a的地址,用16进制的方式
(5)指针变量名间接应用了一个值,我们使用间接引用运算符来取得具体的值
printf (”%d”, *aptr);
(6)指针必须初始化,可以把指针初始化为NULL
NULL在中定义,它的值是0
使用NULL使程序具有可读性。
注意:
& 取地址运算符 取得任何变量的地址
如:
int a;
int *aptr;
int c[5];
//使用&运算符取得地址,并打印出来
printf ("%p\n", &a);//取得整型变量a的内存地址
printf ("%p\n", &aptr);//取得指针变量aptr的内存地址
printf ("%p\n", &c[0]);//取得数组第一个元素的内存地址
* 比较让大家迷惑的是它在这里有两种不同的用法,但实际上它们并不是同样的
(1)和具体的数据类型一起构成对应的指针类型
*在声明语句表示变量是一个指针
int *
float *
char *
double *
(2)间接引用运算符
int a = 3;
int * aptr = &a;//把a的地址通过取地址运算符赋给指针变量 aptr
printf ("%d", *aptr);//通过a的地址间接引用变量a的值
思考:
仔细分析下面的语句的结果。
int a = 8;
int * aPtr;
aPtr = &a;
printf ("%p\n", & * aPtr);
printf ("%p\n", * & aPtr);
提示,一层层分析,可以看做 &(*aPtr)
答案在最下面。
二、指针的传引用调用
1.C语言中所有的函数都是传值调用
为什么,难道指针不是传引用调用吗?
不是,C语言只是把指针的值拷贝一份,传如函数内部。
2.那么传递数组呢?
void printArray (int *nPtr);
和
void printArray (int array[]);
的效果都是一样的,都是传一个地址进去。
另外,要注意:
数组名本身就是地址。
3.指针的传引用调用我们也可称之为模拟传引用调用,因为我们传的是一个地址,
函数调用时,函数的参数会拷贝这个地址,然后通过复引用来操作变量。
int cubeByReference (int * nPtr)//计算立方
{
*nptr = *nptr * *nptr * *nptr;
}
注意这里,
(1)*(复引用运算符)比*(乘法运算符)优先级要高。
所以可以不适用括号,但是推荐你使用下面的语句,这样程序更加清晰。
(2)nPtr是占用堆栈的,函数cubeByReference会给nPtr这个指针变量分配空间,
然后把传入的指针变量的值赋给它。
int cubeByReference (int * nPtr)//计算立方
{
(*nptr) = (*nptr) * (*nptr) * (*nptr);
}
4.传值为什么不改变传入变量的值
因为它是在堆栈中生成一个新的变量,然后把存放的值拷贝过来,最后函数结束的时候把该变量从堆栈中释
放掉,所以并不会改变传入变量的值。
就像你用一张新的纸把一张纸上的东西复制一遍,然后在新的纸上写写画画,然后丢掉,并不会影响到原来
的纸上的内容。
5.传指针(也就是传引用为什么会改变)
因为指针给出了原来变量的地址,使得*(复引用指针)可以通过这个地址找到这个变量并对它进行修改。
三、指针的const限定
(1)指向非常量数据的非常量指针
int a;
int b;
int *aPtr;
aPtr = &a;//OK
aPtr = &b;//OK
*aptr = 3;//OK
(2)指向常量数据的非常量指针(不能修改指向变量中的数据)
const int * aPtr;
注意:const 修饰int
int a;
int b;
const int *aPtr;
aPtr = &a;//OK
aPtr = &b;//OK
*aptr = 3;//ERROR 不能修改指向的变量中的数据
(3)指向非常量数据的常量指针(不能东指西指)
int * const aPtr;
注意: const 修饰指针变量 aptr;
数组名是一个很好的例子。(参见字符串数组中的说明。)
int a;
int b;
const int *aPtr = &a;
aPtr = &b;//ERROR 不能再指向另外一个变量
*aptr = 3;//OK
(4)指向常量数据的常量指针(不能修改指向变量中的数据,不能东指西指)
const int * const aPtr;
int a;
int b;
const int * const aPtr = &a;
aPtr = &b;//ERROR 不能再指向另外一个变量
*aptr = 3;//ERROR 不能修改指向的变量中的数据
答案:
1.实际上*aPtr相当于a, &*aPtr就取得a的地址
2.&aPtr取得aPtr的直至,而*&aPtr就取得aPtr存放的值,也就是a的地址
3.&*会相互抵消,实际上&*aPtr == aPtr == *&aPtr