目录
指针与数组
传入函数的数组成了什么?
void test(int a[]);
int main() {
int a[]={1,2,3,4,5,};
printf("main sizeof(a)=%lu\n",sizeof(a));
test(a);
return 0;
}
void test(int a[])
{
printf("test sizeof(a)=%lu\n",sizeof(a));
}
从结果发现:主函数中的sizeof得出的就是5个int的大小
而传入函数中的数组就是一个指针的大小
分别打印main中a的地址和函数中的地址
证明是同一个
在函数中给a[0]赋值
a[0]=1000;
在主函数中打印a[0]
printf("a[0]=%d\n",a[0]);
所以实际上就是个指针
甚至在声明函数时可以直接这么写
void test(int *a)
运行结果不会变
实际上数组变量是const指针,所以不能被赋值
也就是不能:int b[]=a;
但是可以int *q=a
他们有什么不同呢?
实际上int []b可以看做int * const b;表示b指针是个常量只能指向(代表)这个数组
被初始化出来就不能改变了
小结:
函数参数列表中的数组实际上是指针
sizeof(a)==size(int*)
但是可以用数组的运算符[]进行运算
以下四种函数原型是等价的
数组变量是特殊的指针
数组变量本身表达地址
int a[10]; int*p=a //无需用&取地址
但是数组的单元表达的是变量,需要用&取地址
a==&a[0]
[]运算符可以对数组做也可以对指针做
p[0]<==>a[0]
示例
inti=10;
int*p=&i;
printf("*p=%d\n",*p);
printf("p[0]=%d\n",p[0]);//把所指向的变量当做容量只有1的数组p[0]就是取第一个,但是不能这么写:i[0];
//小实验
int *q[2];
q[0]=&i;
q[1]=&i;
printf("%d\n",q[1][0]);//实验得出这不是个二维数组而是指针数组使用了[0]取值
那么同样*也可以对数组使用
int a[]={1,3,2,42,7,};
printf("*a=%d\n",*a);
把数组当指针用就可以了
指针与const
注:只适用于c99
表示一旦得到了某个变量的地址,不能再指向其他变量
例如:
int *const q=&I;
*q=26;//ok
q++;//error
所指是const
表示不能通过这个指针去修改那个变量(并不能使得那个变量成为const)
const int *p=&i;
*p=26;//error! (*p)是const
i=26;//ok
p=&j;//ok
意思是变量并不是const,指针也可以指向别的变量,但是不能通过*p去改变变量的值
这些是啥意思?
判断哪个被const了的标志是const在*前面还是后面
如果在*前面表示它所指的东西不能(*p=?)被修改
如果在*后面表示指针不能被修改
转换
总是可以把一个(传进来的参数)非const的值转换成const的
有一个函数:void f(const int* x);
int a=15;
f(&a);//将a的地址穿进去ok
const int b=a;
f(&b);//将一个本来就是const 的变量传进去也ok
但是在函数中执行
b+a+1;//error
当要传递的参数类型比地址大的时候,这是常用的手段:既能用比较少的字节数传递值给参数,又能避免函数对外面的变量进行修改
const数组
const int a[]={1,2,3,4,5,6};
数组变量已经是const的指针了,这里的const表明数组的每个单元都是const int
所以必须通过初始化进行赋值
保护数组值
因为把数组传入函数时传递的是地址,所以那个函数可以修改数组的值,为了保护数组不被函数破坏可以设置参数为const
int sum(const int a[],int length);
指针运算
char ac[]={0,1,2,3,4,5,6,7,8,9,};
char *p=ac;
printf("p=%p\n",p);
printf("p+1=%p\n",p+1);//sizeof(char)=1
int ac2[]={0,1,2,3,4,5,6,7,8,9,};
int *p2=ac2;
printf("p2=%p\n",p2);
printf("p2+1=%p\n",p2+1);//sizeof(int)=4
printf("*p2+1=%d",*(p2+1));
//所以指针加1就是指向数组的下一个单元,实际上加的是sizeof
return 0;
*(p+1)-->a[1]
为什么要这么做?因为
直接将地址+1是无意义的,如果指针不是指向一片连续分配的空间如数组则这种运算没有意义,所以+1就是加一个sizeof
既然可以加则也可以减,p++,p--
两个指针相减
char ac[]={0,1,2,3,4,5,6,7,8,9,};
char *p=ac;
char *p1=&ac[5];
printf("p1-p=%d\n",p1-p);
int ai[]={0,1,2,3,4,5,6,7,8,9,};
int *q=ai;
int *q1=&ai[5];
printf("q1-q=%d\n",q1-q);
return 0;
表示两个指针间能放多少个这样的变量
*p++
去除p所指的那个数据来完事之后顺便把p移到下一个位置去
*的优先级虽然高,但是没有++高
常用于数组类的连续空间操作
在某些cpu上,这可以直接被翻译成一条汇编指令
数组两种遍历方式
第一种
printf("q1-q=%d\n",q1-q);
for (int i = 0; i < sizeof(ai) / sizeof(ai[0]); ++i) {
printf("%d\n",*q++);
}
q=ai;
第二种
while (*q != -1){
printf("%d\n",*q++);
}
用指针来做什么
1、需要传入较大的数据时用作参数
2、传入数组后对数组做操作
3、函数返回不止一个结果
4、需要用函数来修改不止一个变量
5、动态申请的内存…
动态内存分配
输入数据问题:输入数据时,先告诉个数后再输入,要记录每个数据
c99可以用变量做数组定义的大小,C99之前呢?
使用动态内存分配
写法: int*a=(int*)malloc(n*size(int));
意思:malloc函数参数是需要的内存大小,n是要输入的变量数量,sizeof(int)代表要int所以是4个字节
最后申请出来的是void*类型,使用(int*)强制转换成int类型
例如:我要120个字节,就是30个int,30*sizeof(int)=120
使用该函数需要#include<stdlib.h>
参数类型是一个size_t 现在不讲
返回值是 void*
对于c语言来说,无法传递一个类型,只能告诉malloc要多少个字节
计组知识:1个字是的大小取决于地址线根数,也是一次传输能传送的最大位数,32位下一个字=4字节,64位下是=8字节
动态分配空间示例(重点)
intnumber;
int*a;
inti;
printf("输入数量:");
scanf("%d",&number);
//inta[number];//c99做法
a=(int*)malloc(number*sizeof(int));
//因为指针和数组是一样的,所以之后指针a就当做数组用就好了
for(i=0;i<number;i++)
{
scanf("%d",&a[i]);
}
for(i=number-1;i>=0;i--)//逆序遍历
{
printf("%d",a[i]);
}
//空间用完了要还给系统
free(a);
malloc和free成对出现,申请过的空间,最终都应该要还
free()把申请来的空间换给系统,但是只能还申请来空间的首地址
void* p;
p = malloc(100 * 1024 * 1024);
p++;
free(p);
如果如以上代码p++之后释放p,就会报错:要释放的指针不是申请来的
void *p;
int i;
p=&i;
free(p);//错误
同样不能释放定义的变量空间,且随便指定一个地址比如1也会报错
但是可以释放NULL,因为free函数里面有个判断如果地址是0则不作任何事情,所以定义指针时注意初始化为0
引用csdn的文章内容:
1.用malloc来分配的内存应该把它free掉,否则在那些空间不再使用时,程序仍然占用大量的内存.malloc可以单独出现,但是一般我们都不这样做!!
2.如果不是用malloc来分配的,就无需free,就是说,free不可以单独出现在程序中,否则会无缘无故的回收内存空间,后果将会很严重.
常见问题:
申请了没free会长时间运行内存逐渐下降
新手:忘了
老手:找不到合适的free时机
虽然程序结束所有的内存漏洞(垃圾)都会被操作系统清除,但是在大型项目里(比如服务器),就必须free。
free过了再free
地址变过来,直接去free
没空间了怎么办?
如果申请失败则返回0,或则叫做NULL
你的系统能给你多大的空间?
#include <stdio.h>
#include<stdlib.h>
int main() {
void* p;
int cnt = 0;
while ((p = malloc(100 * 1024 * 1024))) {//1024是1k,100*1024^2=100Mb,while执行到p=0为止
cnt++;
}
printf("分配了%d00MB的空间\n", cnt);
return 0;
64位的结果
32位的结果