目录
一、指针相关定义
符号: *p
定义:指针即内存地址,而指针变量是用来存放内存地址的变量。
特点:可对存储数据的变量地址进行操作。
性质:不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。
指针描述了数据在内存中的位置,标示了一个占据存储空间的实体,在这一段空间起始位置的相对距离值。
*是一个单目运算符,用来访问指针的值所表示的地址上的变量
可以做右值读取,也可以做左值写入
int k =*p;(读取)
*p = k+1;(写入)
-
p是一个地址
-
*p是一个值
#include<stdio.h>
void a(int* p);
void b(int i);
int main(void)
{
int i = 6;
printf("&i=%p\n", &i);
int * p;
p = &i; //初始化
*p = 12;
printf("%p\n", &i);
a(&i);
b(i);
return 0;
}
void a(int* p)
{
printf("p = % p\n", p);
printf("*p=%d\n", *p);
}
void b(int k)
{
printf("k=%d\n", k);
}
如图:
可见:当值改变时地址并没有改变
-
p是一个地址,用%p打印
-
*p是一个值,可以通过改变 *p来改变原本 i 的值
注:任何一个*p在没有得到实际变量的地址之前,是不能对其进行赋值的(初始化) 可能不会报错,但是需要注意。
二、数组与指针
1.数组变量是特殊的指针
传入函数的数组成了什么?,函数参数表中的数组实际上是指针。
- sizeof(a) == sizeof(int*)
数组参数
以下四种函数原型是等价的:
int sum(int *ar, int n);
int sum(int ar[], int n);
int sum(int *, int);
int sum(int [], int);
注:void fun(int n);//这就是函数原型。
它们的类型并不一样,而是说如果它们在参数表中出现,作为函数原型,它们是等价的。
数组变量本身表达地址
int a[10]; int *p=a; // 直接用数组变量名,无需用&取地址
a == &a[0]; //但是当数组的单元表达的是单个变量,需要用&取地址
[]运算符可以对数组做,也可以对指针做:
p[0] <==> a[0]
*
运算符可以对指针做,也可以对数组做:
*a=25;
数组变量是const
的指针,所以不能被赋值
int a[ ] <==> int* const a=……
2.指针与const
指针是const,一旦指向一个变量的地址,就不能再指向其他变量
#include<stdio.h>
int main
{
int * const p = &i; //一旦指向一个变量的地址,不能再指向其他变量
*p = 26; //ok
p++;//wrong
}
a、所指是const时
不能通过该指针去修改该变量,原变量i仍然可以修改
#include<stdio.h>
int main
{
int const *p = &i;//不能通过该指针去修改该变量,原变量i仍然可以修改
*p = 26;//error!
i = 26;//ok 因为i不是const
p = &j; // ok
}
b、const转化
总是可以把一个非const的值转换成const的值
#include<stdio.h>
int main
{
int a = 15; f(&a); // OK
const int b = a; f(&b); // OK
b = a+1; //Error! const不能再改变
}
运用const转化:保护数组值不被函数破坏
如:
int sum(const int a[], int length);
又因为把数组传入函数时传递的是地址,所以那个函数内部可以修改数组的值
c、const数组
初始化
const int a[] = {1,2,3,4,5,6,};
- 数组变量是const的指针,这里的const表面数组的每个单元都是const int
- 所以必须通过初始化进行赋值
三、指针运算
指针+1:
#include<stdio.h>
int main(void)
{
char ac[] = { 0,1,2,3,4,5 };
char* p = ac;
printf("p=%p\n", p);
printf("p+1=%p\n", p + 1);
int ai[] = { 0,1,2,3,4,5};
int* q = ai;
printf("q = % p\n", q);
printf("q+1=%p\n", q + 1);
}
运行如下:
- 可见,是加上一个sizeof指针类型,如char一个单元占据1字节,int一个单元占据4字节
*p++
- 取出p所在的位置,并把把p移到下一个位置去
*
的优先级虽然高,但是没有+
高- 常用于数组的连续空间操作
- 在某些cpu上,可以直接被翻译成一条汇编指令
注:*属于单目运算符, 运算*(p+1)时 ,需要用上小括号,否则先运算+
四、指针比较
- <,<=,==,>,>=,!= 都可以对指针做
- 比较它们在内存中的地址
- 数组中的单元的地址肯定是线性递增的
注:指针不可以做乘除,这没有任何意义
0地址
- 现代操作系统都是多进程操作系统,它的基本管理单元是进程。
- 操作系统会给进程分配一个虚拟的地址空间,所有的程序在运行时都以为自己具有从0开始的一片连续空间。
但是指针不应该具有0值。
我们可以用0地址来表示特殊的事情:
- 返回的指针是无效的
- 指针没有被真正初始化(先初始化为0)
Null是一个预定定义的符号,表示0地址。