学习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