指针变量
1、指针的概念
什么是指针?一个内存变量或数组变量在内存中的地址就是指针,或者说,内存地址就是指针,指针就是内存地址。
2、指针变量的定义
指针变量的定义,其实就是在普通变量的变量的定义只多了一个*符号。
格式:
变量类型 * 指针变量名称[=地址];
例如:int i=0;
int *p=&i;//其中&符号是取地址符号,用于获取一个变量的地址。
注意:
-
*符号的左边和右边可以各有一个空格间隔,这样书写代码显得更清晰一些。
-
*符号两旁都没有空格或者左边或右边有一个空格都是可以的,就如同赋值符号两边可以有空格也可以没有空格一样。
测试指针变量空间大小的值
#include<stdio.h>
int main() {
int i = 0; int* p = &i;
printf("指针变量p的空间地址为%p\n",p);
printf("指针变量p的空间大小为%d\n",sizeof(p));
return 0;
}
3、指针变量的功能
对所指向的内存地址上的数据进行读取或写入操作
测试指针变量的功能
#include<stdio.h>
int main() {
int i = 0; int* p = &i;
printf("指针变量p的空间地址为%p\n",p);
printf("指针变量p所指向的数据值:%d\n",*p);//输出结果0
*p = 666;
printf("指针变量p所指向的数据值: %d\n", *p);//输出结果666
return 0;
}
4、指针变量与数组
指针变量也可以使用类似于数组的下标符号[],对目标内存(变量空间进行读或写的操作。
//例如:
int i=666;
int*p=&ip[0]=-1; //*p=-1; 这两种写法是等价的!
指针变量对目标内存空间进行读写操作的两种方式:
•通过指针变量与*符号对指向的内存操作;
•使用下标符号[]与指针变量联合来读写目标内存中的数据。
测试指针变量与数组
#include<stdio.h>
#include <stdlib.h>
int main(){
int a[] = { 8,5,6,2,5 };
int i = 0; int* p = a;
while (i <sizeof(a)/sizeof(a[0]))
printf("%d ", p[i++]);
p = &i; printf("\n数组元素的个数是:%d", p[0]);
//p[0] 与 *p 是等价写法
printf("\n数组元素的个数是:%d", *p);
//p[0] 与 *p 是等价写法
return 0;
}
5、指针变量原则
对一个变量取地址的结果是指针常量,我们熟悉的一个数组名其实就是指针常量。
int a[10],i=10;
int *p = a;
//数组a只能做右值不能做左值
p=&i;
//&i也是只能做右值不能做左值,而可以做左值的p就是指针变量
5.1、指针变量的赋值原则
•右值必须是指针变量或者指针常量,不可以是一个整数或者浮点数。
int *p = 1; //错误:不能使用整数常量赋值
int i=2,*p1 = i; //错误: p1是指针变量,i是整型变量
•只有一个整数可以赋值给指针变量,那就是0,0代表空指针或空地址
int *p=0; //可以使用空地址对指针变量初始化
•右值必须是相同类型的指针变量或者常量(除非使用强制转换语句)。
int i = 1;int *p=&i; //正确:类型相同
char*pc =p; //错误:类型不同
• 同时定义两个指针变量时,每个指针变量前面都要带有*符号。
int i = 10;
//int p1=&i,p2=p1; //错误:p2是int类型
int *p1=&i,*p2=p1; //正确:p2是int类型
5.2、指针变量的使用原则
• 指针加减(p+n)
假如现在有一个未知类型的指针变量p和一个整型常量n。
那么思考:p+n之后的地址与p指向的地址之间,最终相差的物理距离是多少?
其实,p+n的地址偏移与指针变量的类型有关,请大家看下面的例子:
- 如果是char*类型,p+n偏移n个字节;
#include <stdio.h>
int main(){
char a = 'x';
char* b = &a;
int i = 0;
for (i; i < 10;i++) {
char* p = b + i;
printf("指针变量p[%d]的地址是%p\n",i,p);
}
return 0;
}
- 如果是short* 类型,p+n偏移n*2个字节;
# include <stdio.h>
int main(){
short a = 'x';
short* b = &a;
int i = 0;
for (i; i < 10;i++) {
short* p = b + i;
printf("指针变量p[%d]的地址是%p\n",i,p);
}
return 0;
}
- 如果是int* 类型, p+n偏移n*4个字节
# include <stdio.h>
int main(){
int a = 100;
int * b = &a;
int i = 0;
for (i; i < 10;i++) {
int * p = b + i;
printf("指针变量p[%d]的地址是%p\n",i,p);
}
return 0;
}
- 如果是double* 类型,p+n偏移n*8个字节。
# include <stdio.h>
int main(){
double a = 100.00;
double * b = &a;
int i = 0;
for (i; i < 10;i++) {
double * p = b + i;
printf("指针变量p[%d]的地址是%p\n",i,p);
}
return 0;
}
6、指针变量做参数
C语言中,特殊类型的指针变量主要包括:常量指针、指针常量和无类型指针
•常量指针:指向常量区的指针变量
例如:const int* p;
•指针常量:指针变量中的常量
例如:int* const p;
•无类型指针:只记录地址不记录类型的指针变量
例如:void* p;
•常量指针
例如:const char* p;
常量指针的应用:
#include<stdio.h>
int main(){
const int a[10] = { 8,12,38,54 }, b = a[4];
const int* p = a;//常量指针
int i = 0;
while (*p)
printf("%d ", *p++); //*p = 10; 编译时报错!
p = &b;
printf("%d\n", *p); //*p = 10; 编译时报错!
return 0;
}
常量指针的特点:
Ⅰ、常量指针阻止修改指针指向内存的数值
例如:const char* p = "xiaokenan";
//字符串常量原本的类型就是常量指针的类
Ⅱ、常量指针禁止对目标数据赋值操作,允许读取操作,允许偏移操作
const char* p = "xiaokenan";
p = p+1; //可以,是允许指向变动的
char c = *p; //可以,只读
p[0] ='s'; //不可以,指针指向内存的数值是不允许被修改的
Ⅲ、常量指针最常用于做参数,目的保护被调函数内的实参,在被调函数执行过程中不被修改
#include<stdio.h>
int Calcal(const int* p) {
int nSum = 0;
while (*p)
nSum += *p++;
//*p = 6;//编译错误,不能修改!
return nSum;
}
int main() {
int a[] = { 1,2,3,4,5,6 };
int n = Calcal(a);
printf("你输入的数字总和为:%d\n", n);
return 0;
}
•指针常量
Ⅰ、定义指针常量的格式:类型 * const变量名=地址;
int n=10l;
int* const p=&n;//指针常量必须初始化
Ⅱ、指针常量的应用:
#include<stdio.h>
int main() {
int a[] = { 1,2,3,4,5,6 }, n = 666;
//int * const p 错误:必须初始化
int* const p = a;//常量指针
//++p; 不可以,不能执行偏移操作
//p = &n; 不可以,不能指向新的地址
*p = n; //可以,可以对目标内存执行写入操作
printf("a[0]=%d\n", a[0]);
return 0;
}
Ⅲ、指针常量的特点:
- 指向固定的位置的指针变量,格式是const在指针变量前星号后。
int n=100; int* const p = &n;
- 禁止偏移操作,允许对数据赋值操作和读取操作
p=p+1; //错误
int c=p[0]; //正确
*p=100; //正确
p[0]=100; //正确
// *p和p[0]的类型是int类型,不是const int类型
- 指针常量必须初始化
int* const p; //错误
•无类型指针
Ⅰ、定义无类型指针的格式:void* 变量名;
void* p=NULL;
Ⅱ、无类型指针的特点:
- *p和p[0]的类型是未知类型,禁止赋值与取值
*p=100; //编译错误
p[0]=100; //编译错误
- 禁止对目标数据赋值操作和读取操作,允许指向任何新地址,但又禁止自增加自减
double d = 10;p=&d; //编译正确
++p; //编译错误
- 如果要对无类型指针指向的内存操作,必须先强制转化为一种具体类型。
double pc = (double)p;
*pc=66.4;
//无类型指针最常用于做形式参数,功能是对任何类型的实参都可以自动匹配
7、const关键字的作用
const是在*符号之前定义的指针变量就是常量指针,如果const在 * 符号之后定义的指针变量就是指针常量。
指针常量:指针里面所存储的内容(内存地址)是常量,不能改变。但是,内存地址所对应的内容是可以通过指针改变的
常量指针:指针指向的是常量,它指向的内容不能发生改变,不能通过指针来修改它指向的内容。但是,指针自身不是常量,它自身的值可以改变,从而指向另一个常量。