int main(void) {
int * p;//p是变量的名字,int * 类型表示p变量存放的是 int 类型变量的地址
int i=3;
int j;
// p=i// error 因为类型不一致,p只能存放 int 类型变量的地址,不能存放int 类型变量的值
// p=5;//error 原因同上
p=&i;/*
1.p 保存了 i 的地址,因此 p 指向 i ,
2.但是p不是i,i也不是p,更准确的说,修改p的值不影响i的值,修改i的值也不影响p的值
3.如果一个指针变量指向了某个普通变量, 则 *指针变量 就完全等同于 普通变量
例子:如果p是个指针变量,并且p存放了普通变量i的地址
则p指向了普通变量
*p 就完全等同于 i
或者说:在所有出现 * p的地方都可以替换成 i ,在所有出现 i 的地方都可以替换成 * p
* p 就是以p的内容为地址的变量
*/
j=*p;//等价于j=i
printf("i=%d,j=%d,*p=%d\n",i,j,*p);3,3,3
return 0;
}
}
指针就是地址,地址就是指针
地址就是内存单元的编号
指针变量是存放地址的变量
指针和指针变量是两个不同的概念
但是要注意:通常我们叙述时会把指针变量简称为指针,实际他们含义并不一样。
内存单元的编号
从0开始的非负整数
范围:4G(0——4G-1)
指针就是地址,地址就是指针
指针变量就是存放内存单元编号的变量,或者说指针变量就是存放地址的变量
指针和指针变量是两个不同的概念
但是要注意:通常我们叙述时会把指针变量简称为指针,实际他们含义并不一样。
指针的本质就是一个操作受限的非负整数(不能乘除)
#include
void huh(int * p,int * q){
int t;//如果要互换*p和*q的值,则t必须定义成int,不能定义成int *,否则语法会出错
t=*p;//p 是int *,*p是int
*p=*q;
*q=t;
return ;
}
int main(void)
{
int a=3;
int b=5;
huh(&a,&b);
printf("a=%d,b=%d",a,b);
return 0;
}
#include
int main(void){
int a[5];//a是数组名,5是数组元素的个数,元素就是变量a[0]--a[4]
int a[3][4];//3行4列,a[0][0]代表第一个元素,a[i][j]代表第i+1行,j+1列元素
int b[5];
// a=b;//error
printf("%#X\n",&a[0]);//0X62FE00
printf("%#X\n",a);//0X62FE00
return 0;
}
2->下标和指针的关系
如果p是个指针变量,则p[i]永远等价于 *(p+i)
int a[5]={0,1,2,3,4};
printf("%d\n",a[3]);//3
printf("%d\n",*(a+3));//3
3->确定一个一维数组需要几个参数(如果一个函数要处理一个一维数组,则需要接收该数组的那些信息)
需要两个参数:数组第一个元素的地址,数组的长度
void f(int *pArr,int len){
// int i;
// for(i=0;i
// printf("%d\n",*(pArr+i));//*(pArr+i)等价于pArr[i],a[i],*(a+i)//1,2,3,4,5
// }
pArr[3]=88;
}
int a[5]={1,2,3,4,5};
int b[6]={-1,-2,-3,-4,-5,6};
int c[100]={99,22,88};
printf("%d\n",a[3]);//4
f(a,5);
printf("%d\n",a[3]);//88
4->指针变量的运算
指针变量不能相加,不能相乘,也不能相除;
如果两个指针变量指向的是同一块连续空间中的不同存储单元,则这两个指针变量才可以相减。
int main(void){
int i=5;
int j=10;
int *p=&i;
int *q=&j;
//p-q没有实际意义
int a[5];
p= &a[1];
q=&a[4];
printf("p,q所指向的单元相隔%d个单元",q-p);//p,q所指向的单元相隔3个单元
return 0;
}
char ch='A';
int i=99;
double x=66.6;
char *p=&ch;
int *q=&i;
double *r=&x;
printf("%d,%d,%d\n",sizeof(p),sizeof(q),sizeof(r));//8,8,8
传统形式定义的数组,该数组的内存程序员无法手动释放。
数组一旦定义,系统为该数组分配的存储空间就会一直存在,除非数组所在的函数运行结束。
在一个函数运行期间,系统为该函数中数组所分配的空间会一直存在,直到该函数运行完毕时,数组的空间才会被系统释放。
**数组的长度一旦定义,其长度就不能再改变。**数组的长度不能在函数运行的过程中动态的扩充或缩小。
A函数定义的数组,在A函数运行期间可以被其他函数使用,但A函数运行完毕之后,A函数中的数组将无法再被其他函数使用。
传统方式定义的数组不能跨函数使用
动态数组很好的解决了传统数组的这四个缺陷
传统数组也叫静态数组
#include
#include
int main(void){
int i=5;//分配了4个字节,静态分配 5行
int *p=(int *)malloc(4); //6行
/*
1.要使用malloch函数,必须添加malloc.h这个头文件
2.malloc 函数只有一个形参,并且形参时整数类型
3.4表示请求系统为本程序分配4个字节
4.malloc函数只能返回第一个字节的地址
5. 6行分配了8(int *p)+4(malloc请求分配的)个字节 。
(p变量占了8个(64位系统),p指向的内存占了4个)
6. p本身所占的内存时静态分配的,而p所指向的内存时动态分配的
*/
*p=5;//*p代表的就是一个int变量,只不过*p这个整型变量的内存分配方式和 5行的i变量的分配方式不同
free(p);//表示把p所指向的内存给释放掉。 p本身的内存是静态的,不能由程序员手动释放,p本身的内存只能在p变量所在的函数运行终止时由系统自动释放
return 0;
}
void f(int *q){
// **q=200//error。只有指针变量前可以加*,而*q是int型
*q=200;
// free(q)//把q所指向的内存释放掉 ,本语句必须注释掉,否则会导致第20行的代码出错
}
int main(void){
int *p=(int *)malloc(sizeof(int));//sizeof(int)返回值时int所占的字节数
*p=10;
printf("%d\n",*p);//10
f(p);
printf("%d\n",*p);//200 20行
return 0;
}
int main(void){
int a[5];//如果int占4个字节的话,则本数组总共包含由20个字节,每四个字节被当作了一个int变量来使用
int len;
int * pArr;
int i;
//动态的构造一维数组
printf("请输入你要存放的元素的个数:");
scanf("%d",&len);
pArr=(int *)malloc(4*len);//本行动态的构造了一个一维数组,该一维数组的长度是len,该数组的数组名是pArr,该数组的每个元素是int类型。类似于int pArr[len];
//对一维数组进行操作, 如对动态一维数组进行赋值
for(i=0;i<len;i++){
printf("请输入第%d个数:",i+1);
scanf("%d",&pArr[i]);
}
//对一维数组进行输出
printf("一维数组的内容是:");
for(i=0;i<len;i++){
printf("%d\t",pArr[i]);
}
free(pArr);//释放掉动态分配的数组
return 0;
}
int main(void){
int i=10;
int * p=&i;
int ** q=&p;
int *** r=&q;
//r=&p;//error 因为r是int ***类型,r只能存放int **类型变量的地址
printf("i=%d\n",***r);//10
return 0;
}
void f(int **q){
int i=5;
// *q就是p
}
void g(){
int i=10;
int *p=&i;
f(&p);//p是int *类型,&p是int ** 类型
}
int main(void){
g();
return 0;
}
#include
#include
void f(int **q){
*q=(int *)malloc(sizeof(int));//sizeof(数据类型)返回值是该数据类型所占的字节数
//等价于p=(int *)malloc(sizeof(int));
//q=5;//error
//*q=5;//error,等价于p=5
**q=5;//*p=5;
}
int main(void){
int *p;
f(&p);
printf("%d\n",*p); //5
return 0;
}