…指针简单来说就是地址(内存单元的编号)
例如:
#include
int main(void)
{
int i = 3;
int * p;//定义指针变量p,p只能存放整型变量的地址。
p = &i;
printf("%d\n",*p);
return 0;
}
3
1、int * p表示定义一个指针变量p,类型为int *代表存放整型变量的地址,p用来存放整型变量的地址。
2、p = &i表示把i的地址存放在p变量里面,则p指向i。这就是指针。
3、当p指向i时,则*p代表取值,指取出p指向的地址的变量i的值(所有出现*p的地方都可以用i替换)。
范围:
一个地址单元就是一个字节(8位二进制)下面是32位的
则一共有2^32个字节。
1kB = 2^10B(字节)
1MB = 2^10KB
1GB = 2^10MB
所以1GB = 2^30B(字节)
2^32B = 4GB
(1)表示一些复杂的数据结构快速的传递数据
(2)使函数返回一个以上的值能直接访问硬件
(3)能够方便的处理字符串
(4)是理解面向对象语言中引用的基础
总结:指针是C语言的灵魂
什么的列子就是基本类型的指针。
下列是常见的一些错误:
代码①:
# include
int main(void)
{
int* p;
int i = 5;
*p = i;
printf("%d\n",*p);
return 0;
}
我们定义了一个存放整型变量的指针变量p,但是p没有指向,所以里面存放的是垃圾值(即p指向的是一个不知名的单元,我们将整数5存放在这个不知名的单元里面,这样是错误的,因为这个不知名的单元不是我们控制的,类似于病毒)
代码②:
# include
int main(void)
{
int* p;
int* q;
int i = 5;
p = &i;
p =q;
printf("%d\n",*p);
return 0;
}
错误和上面一样,q里面的地址是垃圾值,把垃圾值给了p。
改为:
q =p;
printf("%d\n",*q);
经典指针程序互换:
代码①:
# include
void HuHuang(int m,int n)
{
int t;
t = m;
m = n;
n = t;
}
int main(void)
{
int a = 5,b = 3;
HuHuang(a,b);
printf("a = %d,b = %d\n",a,b);
return 0;
}
a = 5,b = 3
调用互换函数时,将a的值赋给了m,将b的值赋给了n。在函数里面实现只是形式参数m和n的值的互换,但printf打印出来的值依然是主函数里面a和b的值。
改进代码②:
# include
/*void HuHuang1(int* m,int* n)
{
int* t;
t = m;
m = n;
n = t;
}*/
//将a的地址赋给m,b的地址赋给n,函数里面交换的只是变量m和n里面的值。
void HuHuang2(int* m,int* n)
{
int t;
t = *m;
*m = *n;
*n = t;
}
/*将a的地址赋给m,b的地址赋给n,*m指向a等同于实参a里面的值(假设a地址为F,I*m代表以F为地址的变量的值)
*n指向b等同于实参b里面的值。*/
int main(void)
{
int a = 5,b = 3;
// HuHuang1(&a,&b);
HuHuang2(&a,&b);
printf("a = %d,b = %d\n",a,b);
return 0;
}
a = 3,b = 5
是指针常量,他存放的是一维数组第一个元素的地址。
# include
int main(void)
{
int a[3] = {1,2,3};
printf("%#X\n",&a[0]);
printf("%#X\n",a);
return 0;
}
0X19FF24
0X19FF24
如果a是一个指针变量,则a[ i ]等价于*(a+i)。
# include
int main(void)
{
int a[3] = {1,2,3};
printf("%d\n",a[1]);
printf("%d\n",*(a+1));
return 0;
}
2
2
需要数组第一个元素的地址
需要数组的长度
代码①:
# include
void f(int* m,int len)//第一个元素的地址和长度
{
int i;
for(i=0 ;i<len ;i++)
printf("%d",*(m+i));//也可以写为m[i],等价于a[i]/b[i],也等价于*(a+i)/*(b+i)
printf("\n");
}
int main(void)
{
int a[3] = {1,2,3};
int b[5] = {1,5,6,8,90};
f(a,3);
f(b,5);
return 0;
}
123
156890
代码②:
# include
void f(int* m,int len)
{
*(m+2) = 11;
}
int main(void)
{
int b[5] = {1,5,6,8,90};
printf("%d\n",b[2]);
f(b,5);
printf("%d\n",b[2]);
return 0;
}
6
11
总结:
可以利用指针,在函数中操作主函数的变量的值,等同于在主函数里面进行操作,进而改变主函数里面变量的值。
指针变量不能相加不能相乘也不能相除
如果两个指针变量指向的是同一块连续空间中的不同存储单元
则这两个指针变量才可以相减
# include
int main(void)
{
int b[5] = {1,5,6,8,90};
int* m;
int* n;
m = &b[1];
n = &b[3];
printf("%d\n",&b[3]-&b[1]);
return 0;
}
2
# include
int main(void)
{
char ch = 'a';
int i = 9;
double j = 6.3;
char* m = &ch;
int* n = &i;
double* h = &j;
printf("%d,%d,%d\n",sizeof(m),sizeof(n),sizeof(h));
return 0;
}
4,4,4
传统数组的缺点:
(1)数组长度必须事先制定,且只能是常整数,不能是变量
例子:
int a[5];//OK
int len = 5; int a[len]; //error
(2)传统形式定义的数组,该数组的内存程序员无法手动释放,在一个函数运行期间,系统为该函数中数组所分配的空间会一直存在,直到该函数运行完毕时,数组的空间才会被系统释放
(3)数组的长度一旦定义,其长度就不能在更改,数组的长度不能在函数运行的过程中动态的扩充或缩小
(4)A函数定义的数组,在A函数运行期间可以被其它函数使用,但A函数运行完毕之后,A函数中的数组将无法在被其他函数使用,传统方式定义的数组不能跨函数使用
为什么需要动态分配内存
动态数组很好的解决了传统数组的这4个缺陷,传统数组也叫静态数组
malloc函数的引入:
# include
# include //调用了malloc函数
int main(void)
{
int i = 5;//分配了4个字节的静态内存(命名为i)
int* p = (int*)malloc(4);//动态分配4个字节的空间(只是这个空间没有命名),然p指向这个空间,
return 0;
/*注意:1、要使用malloc函数,必须要添加头文件
2、malloc函数只能有一个形式参数,并且只能为整型
3、4表示请求系统分配4个字节的空间
4、malloc函数只能返回第一个字节的地址,前面加int*,
表示这个空间是分配给整型变量用的。所以用4个字节
5、p本身所占的内存是静态分配的(4个字节,用于存放动态分
配的空间第一个字节的编号),p所指向的内存是动态分配的
*/
*p = 5;//*p代表就是一个整型变量,只是这个空间是动态分配的
free(p);//表示把p所指向的内存给释放掉,即动态内存释放掉
}
代码①:
# include
# include
void f(int* q)
{
*q = 20;
free(q);
}
int main(void)
{
int* p = (int*)malloc(4);
*p = 10;
printf("%d\n",*p);//10
f(p);
printf("%d\n",*p);//垃圾值:-572662307
return 0;
}
构造动态一维数组:
# include
# include
int main(void)
{
int len,i;
printf("请输入数组元素的个数:");
scanf("%d",&len);
int* p = (int*)malloc(4 * len);//类似于int p[len];
printf("请输入数组的元素,中间以空格隔开:");
//对数组元素的输入
for(i=0 ;i<len ;i++)
scanf("%d",&p[i]);//也可以用*(p+i)
//对数组元素的输出
for(i=0 ;i<len ;i++)
printf("%d ",p[i]);//也可以用*(p+i)
printf("\n");
return 0;
}
请输入数组元素的个数:5
请输入数组的元素,中间以空格隔开:3 2 5 6 4
3 2 5 6 4
纯纯套娃
# include
int main(void)
{
int i = 5;
int* p = &i;
int** q = &p; //q是int**类型,用于存放指针变量p的地址(二级指针)
int*** r = &q; //r是int***类型,用于存放二级指针变量的地址(多级指针)
printf("%d\n",***r);
printf("%d\n",**q);
printf("%d\n",*p);
return 0;
}
#include
void f(int** m)
{
int i = 5;
*m = &i;//*m等于p,p指向i
}
int main(void)
{
int* p;
f(&p);
printf("%d\n",*p);//此行代码存在逻辑上的问题。
return 0;
}
调用f函数结束后,f函数里面的变量值将会被释放,所以*p不能在访问i空间里面的内容。这就是静态变量不能跨函数使用。
动态内存跨函数使用
#include
#include
void f(int** m)//二级指针
{
//int i = 5;//静态分配内存
//*m = &i;//*m等于p,p指向i
*m = (int*)malloc(sizeof(int));//动态分配4个字节(用于存放整型变量)
//的内存,
//等价于p = (int*)malloc(sizeof(int));
**m = 5;//等价于*p = 5
}
int main(void)
{
int* p;
f(&p);//f终止后,空间没有被释放
printf("%d\n",*p);
return 0;
}