您现在的位置是:主页 > news > 重庆忠县网站建设公司推荐/知乎推广合作

重庆忠县网站建设公司推荐/知乎推广合作

admin2025/5/2 5:46:26news

简介重庆忠县网站建设公司推荐,知乎推广合作,好的做详情页的网站有哪些,网站开发公司招聘技术人员文章目录8.1什么是指针8.1.1 什么是指针和指针变量8.2指针变量8.2.1使用指针变量的例子8.2.2 怎样定义指针变量8.2.3 怎样引用指针变量8.2.4指针变量作为函数的参数(例)8.3 通过指针引用数组8.3.1数组元素的指针8.3.2 在引用数组元素时指针的运算8.3.3 通…

重庆忠县网站建设公司推荐,知乎推广合作,好的做详情页的网站有哪些,网站开发公司招聘技术人员文章目录8.1什么是指针8.1.1 什么是指针和指针变量8.2指针变量8.2.1使用指针变量的例子8.2.2 怎样定义指针变量8.2.3 怎样引用指针变量8.2.4指针变量作为函数的参数(例)8.3 通过指针引用数组8.3.1数组元素的指针8.3.2 在引用数组元素时指针的运算8.3.3 通…

文章目录

  • 8.1什么是指针
    • 8.1.1 什么是指针和指针变量
  • 8.2指针变量
    • 8.2.1使用指针变量的例子
    • 8.2.2 怎样定义指针变量
    • 8.2.3 怎样引用指针变量
    • 8.2.4指针变量作为函数的参数(例)
  • 8.3 通过指针引用数组
    • 8.3.1数组元素的指针
    • 8.3.2 在引用数组元素时指针的运算
    • 8.3.3 通过指针引用数组元素
    • 8.3.4 用数组名字作函数参数
    • 8.3.5 多维数组的地址
    • 8.3.6 指向数组元素的指针变量
  • 8.4通过指针引用字符串
    • 8.4.1 字符串的引用方式
    • 8.4.2 字符指针做函数参数
    • 8.4.3 使用字符指针变量和字符数组的比较
  • 8.5指向函数的指针
    • 8.5.1 什么是函数指针
    • 8.5.2 用函数指针变量调用函数
    • 8.5.3 怎样定义和使用指向函数的指针变量
    • 8.5.4 用指向函数的指针作函数变量
  • 8.6 返回指针值的函数
  • 8.7指针数组和多维数组
    • 8.7.1什么是指针数组
    • 8.7.2指向指针数据的指针
    • 8.7.3指针数组作main函数的形参
  • 8.8 动态内存分配与指针变量
    • 8.8.1什么是内存的动态分配
    • 8.8.2怎样建立内存的动态分配
    • 8.8.3void的指针类型

8.1什么是指针

8.1.1 什么是指针和指针变量

首先解决一个问题;数据如何在计算机中储存 ,读取?
直接访问 间接访问
直接访问:

直接访问:
int i;四个字节  :2000  2001  2002  2003
int j;四个字节   :2004  2005  2006  2007 
int k; 四个字节    :2008 2009  2010  2011
在一次编译中,电脑分别给i j k;分配了四个字节 ;不同编译分配的字节地址可能不一样
编译的时候把变量名字转换为变量的地址;
变量名<===>地址
i======>2000...
j======>2004...
k======>2008...
存:电脑找到i,等于找到地址2000,数据存到地址2000中去;
取:电脑找到i,等于找到地址2000,把地址2000中的数据提取出来;

间接访问:

间接访问:
int i;四个字节  :2000  2001  2002  2003
int j;四个字节   :2004  2005  2006  2007 
int k; 四个字节    :2008 2009  2010  2011
把变量i的地址存放到另外一个变量中;然后通过该变量找到该地址,然后访问;
这个变量,是一个“中介”;
i_pointer=&i;(把地址i先储存到变量中去)

把数字3送到i变量中去:

i=3;
*i_pointer=3;
那么由此可以看出i=*i_pointer;后者指的是这个地址所指向的变量i;

那什么是指针,也就是变量的地址;所以,2000,2001…都是指针;如果有一变量专门贮存地址,那么我们称之为指针变量

8.2指针变量

8.2.1使用指针变量的例子

引例:

#include <stdio.h>
int main()
{int a=100,b=10;int *pointer_1,*pinter_2;前面的*只是表示指针变量;pointer_1=&a;pointer_2=&b;printf("%d %d",a,b);printer("*pointer_1:%d,*pointer_2:%d",*pointer_1,*pointer_2);这儿的*表示指向作用;意思是指向指向pointer—1中的地址;就是a;return 0;
}

在这里插入图片描述
&:取地址运算符;
*:指针运算符;

8.2.2 怎样定义指针变量

咱们从例子中可以看到int *pointer_1,*pinter_2;;这就是定义了;所以咱们可以归纳总结为:

类型名 *指针变量名

类型名:定义地址源数据的储存大小,储存方式;
*:表示是后边是指针的变量名;指针变量名字不带 *;比如

:pointer_a;pointer_b;

注意:
1.可以定义的时候初始化;

int *pointer_1=&a,*pinter_2=&b;

2.首先我去取用的时候,*给了pointer_1中的中的东西一个指向的 “魔法加持”,而pointer_1要给 *提供一些东西,就是源数据地址,以及隐含的源数据的几个字节和储存方式;那我有各种各样的数据;比如int ;float ; char ;那我指针变量是不是都能储存呢;不是;只能储存其中一种;所以说定义类型名就是要给这个指针变量限定只能储存按要求的源数据;
3.指针:地址(隐含数据的字节数以及储存方式)
指针变量:一个(限定了源数据具有特定大小;储存条件)只能储存地址的空间

8.2.3 怎样引用指针变量

引用的话就两个;
一个是p:指针变量,里面储存的是地址
一个是*p:地址指向的变量,就是源数据储存变量

例子:
p=&a;这个是把指针变量p引用;把a地址赋值给p;
printf("%d",*p);这个是引用指针变量中的地址,并且给予指向性作用;输出的是a数值
*p=1;把赋值给a;
printf("%d",p);把地址直接输出;

8.2.4指针变量作为函数的参数(例)

/*输入 a,b两个数,按照先大后小的顺序输出a,b;*/#include <stdio.h>int main(){void swap(int *p1,int *p2);int a,b;int *pointer_1,*pointer_2;printf("please enter two integer numbers:");scanf("%d,%d",&a,&b);pointer_1=&a;pointer_2=&b;if(a<b) swap(pointer_1,pointer_2);printf("max=%d,min=%d\n",a,b);return 0;}void swap(int*p1,int*p2){int temp;temp=*p1;*p1 =*p2;*p2=temp;}void swap(int*p1,int*p2){int *temp;*temp=*p1;*p1 =*p2;*p2=*temp;}解释一下这段代码;*temp 这儿定义了指针变量;与前面定义一样,电脑会自己给他分配一个数值先储存进去;同理在这儿如果你没有指定那个变量那么这儿电脑会自动分配某一个变量去指向;那么此时如果你把数值赋值给这个变量,你就会导致这个随意指定的变量的数值改变,导致内部出现未知错误;所以不提议这么做,最好就是定义一个源数据类型的数据形式就行;比如整形;就定义int;

在这里插入图片描述解释一下该函数如何实现的
在这里插入图片描述如上图,

int a,b;
int *pointer_1,*pointer_2;
pointer_1=&a;
pointer_2=&b;

此时就是图(a);

 void swap(int*p1,int*p2)

此时定义了两个形式参数,实参通过“值传递”把地址给了形式参数;在函数里面临时参数等价于一个临时定义的指针变量;这样原指针变量中的地址就给了现在这个指针;所以说如图b(2)左边图的意思;再看如图2

	int temp;temp=*p1;*p1 =*p2;*p2=temp;

这串代码的意思是通过一个临时定义的变量储存空间,把指向的变量的值互换,由于指向的变量不属于临时变量,所以在主函数里面他们的数值真的互换了;所以输出的时候他们的数值就是互换的数值;

通过上面例子我们知道了 void swap(int *p1,int *p2); 做实参;一般而言,普通实参会返回一个数值;当实参是指针的时候,这样的返回值可能就是不只一个;会有多个数值的改变;

8.3 通过指针引用数组

8.3.1数组元素的指针

数组是由若干个数据组成的,所以我的指针变量是可以指向其中某一个数据的;

int a[10];
int *p;
p=&a[0];这就是把数组第一位的地址赋值给了p;

还有一种等价形式:

p=&a[0];
p=a;a是数组,把数组赋值给变量p,但是变量p只能接受一个地址,
所以电脑会默认把第一个地址赋值给p;

在这里插入图片描述
但是注意不能写成p=&a,&a中有是个地址,后面变量不能一下接受10个地址;

8.3.2 在引用数组元素时指针的运算

咱们是可以通过a[0]直接计算出该数组中其他变量的地址,这样咱们就可以只定义一个指针变量,能指向数组中所有的元素;

int a[10];
int *p;
p=&a[0];假设是2000;
p+1 ;指向同一个数组中下一个元素;对于int 型p+1的结果不是2001;而是2004;
p-1;指向同一个数组中上一个元素;结果是1996
p=a;2000;a是数组,把数组赋值给变量p,但是变量p只能接受一个地址,
所以电脑会默认把第一个地址赋值给p;假设地址是2000;
p=a+1;相当于2004,与指针变量运算是一样;因为a也可以理解成指针变量;
编译后*(a);其中a是地址;
p=a[1];2004
printf("%d",a[1]);电脑是如何调用a[1]的数值,首先电脑把a[1]当作*(a+1)处理;
然后输出数值;
p++;
++p;
p--;
--p;
p1-p2;两个地址差值,然后除以数组长度;(2020-2012/4

在这里插入图片描述

 #include <stdio.h>int main(){int a[4]={1,2,3,4};
int *p;
p=a;
p=++p; printf("max=%d\n",*(++p));return 0;}

在这里插入图片描述通过以上结论,咱们可以得出,数组a是不可以自增或者自减的;数组是可以加或者减;数组名a指针型常量;是一个固定不变的值;而指针变量p是可以自增自减的;也可以加减;

8.3.3 通过指针引用数组元素

引用一个数组元素,可以使用
下标法:a[i];在编译时转化为*(a+i)
指针法*(a+i);或者*(p+i);那么我*(p+i)也可以写成p[i];不过这个意思是当前p加上3;不一定等于a[3];

/*有一个整型数组a,有10个元素,要求输出数组中的全部元素*/
#include <stdio.h>
int main()
{int a[10];
int i;
printf("please enter 10 integer numbers:");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
for(i=0;i<10;i++)
printf("%d",a[i]);
printf("%\n");
return 0;} /*有一个整型数组a,有10个元素,要求输出数组中的全部元素*/
#include <stdio.h>
int main()
{int a[10];
int i;
printf("please enter 10 integer numbers:");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
for(i=0;i<10;i++)
printf("%d\t",*(a+i));
printf("%\n");
return 0;} /*有一个整型数组a,有10个元素,要求输出数组中的全部元素*/
#include <stdio.h>
int main()
{int a[10];
int i;
int *p;
printf("please enter 10 integer numbers:");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
for(p=a;p<(a+10);p++)
printf("%d\t",*p);
printf("%\n");
return 0;} /*有一个整型数组a,有10个元素,要求输出数组中的全部元素*/
#include <stdio.h>
int main()
{int a[10];
int i;
int *p=a;
printf("please enter 10 integer numbers:");
for(i=0;i<10;i++)
scanf("%d",&*p++);//后面必须要有地址;*p++不是地址;p++是地址;&*p++是地址;
p=a;
for(i=0;i<10;i++,p++)
printf("%d\t",*p);
printf("\n");
return 0;} 

在这里插入图片描述

*p++   =*(p++) 先用*p ,再让p加一;
*(++p)  先让p加1;然后用*++(*p) 源数据加1

8.3.4 用数组名字作函数参数

从字面意思去理解这个标题数组作函数参数;包括实参还有形参;
具体分为以下四类:
1.形式参数 和 实参都用数组名

inv(a,10);
...
void inv(int x[],int n);

首先函数有实参把数值传给形参;形参是临时定义的;用完自动解散的一个储存单元;
实参用的是数组名,那么我电脑默认数组名传给形参的时候,我给的是数组中第一个地址;而形参定义的是数组,而电脑编译时就相当于x[]=*x;,此时指向的是第一个地址;而x就是指针变量;
2,形参用数组名字,实参用指针变量

inv(a,10);
...
void inv(int *x,int n);

首先函数有实参把数值传给形参;形参是临时定义的;用完自动解散的一个储存单元;
实参用的是数组名,那么我电脑默认数组名传给形参的时候,我给的是数组中第一个地址;而形参定义的是指针变量,此时指向的是第一个地址;而x在函数体中就可以当作指针变量使用;
3,形参用指针变量 实参也用指针变量

int *p;
int(p,10);
...
void inv(int *x,int n);

首先函数有实参把数值传给形参;形参是临时定义的;用完自动解散的一个储存单元;
实参用的是指针变量,实参传给形参的时候,实参中包含的是地址,而我把实参中的地址给了形参而已,而形参定义的是指针变量,此时指向的是第一个地址;而x在函数体中就可以当作指针变量使用;
4,形参用指针变量 实参用数组

int *p;
int(p,10);
...
void inv(int a[],int n);
首先函数有实参把数值传给形参;形参是临时定义的;用完自动解散的一个储存单元;
实参用的是指针变量,实参传给形参的时候,实参中包含的是地址,而我把实参中的地址给了形参而已,而形参定义的是数组名,而电脑在编译的时候,会把数组名当作指针来处理,所以x就相当于定义了一个指针变量,此时指向的是第一个地址;而x在函数体中就可以当作指针变量使用;
/*将数组中a个整数按照相反顺序存放*
#include <stdio.h>
int main()
{void inv(int x[],int n);
int i,a[10]={3,7,9,11,0,6,7,5,4,2};
printf("the original arrary:\n");
for(i=0;i<10;i++)
printf("%d\t",a[i]);
printf("\n");
inv(a,10);
printf("the array has bee inverted :\n");
for(i=0;i<10;i++)
printf("%d\t",a[i]);
printf("\n");
return 0;
} void inv(int x[],int n)
{int temp,i,j,m=(n-1)/2;//m=4;
for(i=0;i<=m;i++)//循环5次,因为\\a0 a9\\a1 a8\\a2 a7\\a3 a6\\a4 a5\\
{
j=n-1-i;//当i都等于0时候,j=9;...
temp=x[i];
x[i]=x[j];
x[j]=temp; //把数值交换
}
return ;
} *//*将数组中a个整数按照相反顺序存放*/ 
#include <stdio.h>
int main()
{void inv(int *x,int n);
int i,a[10]={3,7,9,11,0,6,7,5,4,2};
printf("the original arrary:\n");
for(i=0;i<10;i++)
printf("%d\t",a[i]);
printf("\n");
inv(a,10);
printf("the array has bee inverted :\n");
for(i=0;i<10;i++)
printf("%d\t",a[i]);
printf("\n");
return 0;
} void inv(int *x,int n)
{int *p,temp,*i,*j,m=(n-1)/2;
i=x;j=x+n-1;p=x+m; 
for(;i<=p;i++,j--){
temp=*i;*i=*j;
*j=temp;
}
return ;
} 

在这里插入图片描述

8.3.5 多维数组的地址

a;表示一维数组第一个元素的首地址;假设是2000
a+1;表示一维数组第二个元素的地址;2004
a+2;表示一维数组第三个元素的地址;2008
他们代表的含义是具体某一个元素的地址;
二维数组:
a;第0行一维数组的地址;2000;
a+1;第1行一维数组的地址;2016;
a+2;第2行一维数组的地址;2032;
他们所代表的含义都不是某一个具体元素的地址;
但是地址的数值本身可能和某一具体的地址重合;
///
把二维数组中的某一行四个元素都理解成一个抽象的新元素;
这样二维数组就变成了含有四个元素的“一维数组”;
这样a;a+!;a+2;就都是某一抽象元素的具体地址了;
一维数组:
a[0];一维数组中第一个元素,电脑编译时相当于*a;
a[1]; 一维数组中第二个元素,电脑编译时相当于*(a+1;
a[2]; 一维数组中第三个元素,电脑编译时相当于*(a+2;
//
二维数组:
a[0]; 二维数组中第0行;算作是一个抽象的“一维数组”,a[0]是第一个元素的地址;
2000,等价于*a=*(a+0)=&a[0][];a表示行,在行的前面加一个*;
表示把行的地址转化为列的地址;这样2000原本作为第一行的开头地址,
现在变成了第0行第一位元素的具体地址;虽然a与*a
俩个都是2000;但是具体所表示的含义是截然不同的;
a[0]+1; 第二个元素的地址;2004 =*(a)+1=&a[0][1]
a[0]+2; 第三个元素的地址;2008=*(a)+2=&a[0][2]
//

a;第0行一维数组的地址;2000;
a[0]; 二维数组中第0行;算作是一个抽象的“一维数组”,a[0]是第一个元素的地址;2000
这两个地址都是2000;表示的是同一个地址;但是两者的所代表的含义是截然不同的;

二维数组:
a[0][0];
a[0][1];
a[0][2];

*(a[0]+0)=*(a[0])=*(*(a+0)+0)=*(*a)=*(*(a+0))*(a[0]+1)=*(*a+1)
*(a[0]+2)=*(*a+2)

在这里插入图片描述看这张图,第三行有一个&a[1]为什么是一行首地址;这是因为,在指向行的指针前面加上一个*,就直接转化为指向列的指针;同理在指向列的指针前面加上&,就成为指向行的指针;所以原本a[1];是第一行中第一列元素的地址,但是这里把列转化为行了,所以说这里其实就是第1行的地址;

#include <stdio.h>
int main()
{int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
printf("%d %d\n",a,*a);
printf("%d %d\n",a[0],*(a+0));
printf("%d %d\n",&a[0],&a[0][0]);
printf("%d %d\n",a[1],a+1);
printf("%d %d\n",&a[1][0],*(a+1)+0);
printf("%d %d\n",a[2],*(a+2));
printf("%d %d\n",&a[2],a+2);
printf("%d %d\n",a[1][0],*(*(a+1)+0));
printf("%d %d\n",*a[2],*(*(a+2)+0));
return 0; 
}

在这里插入图片描述

8.3.6 指向数组元素的指针变量

a.指向数组元素的指针变量

/*有一个3*4的二维数组,要求用指向多维数组元素的指针变量输出二维数组各个元素的数值*/ 
#include <stdio.h>
int main()
{
int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; 
int *p;
for(p=a[0];p<a[0]+12;p++)
{if((p-a[0])%4==0)printf("\n");
printf("%4d",*p);
}
printf("\n");
return 0;
}
仔细看着这个指针,你会发现*p直接就指向元素本身,就是整型数据的;
p是具体某一个二维数组的地址;比如p是指向a[0];a[0][1];a[0][2];

b.指向m个元素组成的一维数组的指针变量
上面讲到了,他是指向某一个具体的元素的;比如a[0];a[0][0];
这里是不一样的,这次是指向包含了m个元素的一维数组;
这样的话只能这样赋值:
p=a[0];是错误的;改成p=&a[0];

指向某一个具体的数值的指针变量;
p=a[0];含义是把第一行第一列的元素的地址赋值给p;
p+1;表示下一个元素的具体地址;
指向m个元素组成的一维数组的指针变量;
p=&a[0];含义是把第一行的地址赋值给变量p;
p+2;表示下一行一维数组的具体地址;
#include <stdio.h>
int main()
{int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
int(*p)[4];
int i,j;
p=a;
printf("please enter row and colum:");
scanf("%d,%d",&i,&j);
printf("a[%d,%d]=%d\n",i,j,*(*(p+i)+j));
return 0;
}
///
int(*p)[4];
表示定义p为一个指针变量;他指向包含四个元素的一维数组;
p被定义为指向一维整型数组的指针变量,一维数组有四个元素,
因此p的类型是一维数组,包含四个整型数据,其长度是16个字节;
注意!!基类型不是int* ;而是int * [4];
两者是有区别的;前者定义的是整型;后者定义的是一维数组包含四个元素;

在这里插入图片描述3.用指向数组的指针作函数的参数;
可以使用两个东西作为函数的参数(1.指向某一具体元素的指针变量,2.指向某m个元素构成的一维数组的指针变量;)

/*有一个班级,三名学生,各学四门课,计算总平均分数,以及第n个学生的成绩*/
#include <stdio.h>
int main()
{void average(float *p,int n);
void search(float(*p)[4],int n);
float score[3][4]={{65,67,70,60},{80,87,90,81},{90,99,100,98}};
average(*score,12);
search(score,2);
return 0;
} void average(float *p,int n)
{float *p_end;
float sum=0,aver;
p_end=p+n-1;//表示p+11;就是最后一个位置的元素的地址;
for(;p<=p_end;p++)
sum=sukm+(*p);
aver=sum/n;
printf("average=%5.2f\n",aver);
}
///
这一行主要使用了指向数组元素的指针变量,float *p;这样对于p而言;
形式参数里面的初始化的地址就是某一个具体元素的地址;
实参是*score;其含义等价于*a;后者是第一行第一列元素的地址;
所以实参是第一行第一列的元素的地址;
void search(float (*p)[4],int n)
{int i;
printf("the score of no.%d are :\n",n);
for(i=0;i<4;i++)
printf("%5.2f",*(*(p+n)+i));//输出某一个元素的具体值;
printf("\n"); 
}

这一行使用了指向m个元素组成的一维数组的指针变量,float (*p)[4];
这意味着,形式参数的p的所代表的地址是一个个抽象的一维数组的地址的开头;
基类型也是一维数组;实参score;这相当于a;这是第一行一维数组的开头地址;
所以在函数体中,p初始化为第一行一维数组的首地址;

在这里插入图片描述

/*查找一门以上课程不及格的学生,输出他们全部课程的成绩*/
#include <stdio.h>
int main()
{void search(float (*p)[4],int n);
float score[3][4]={{57,67,70,60},{80,87,90,81},{90,99,100,98}};
search(score,3);
return 0;
}void search(float(*p)[4],int n)
{int i,j ,flag;
for(j=0;j<n;j++)
{flag =0;
for(i=0;i<4;i++) if(*(*(p+j)+i)<60) flag=1;
///用的是*(*(p+j)+i)输出某一个具体的数值。
if(flag==1)
{printf("no.%d fails,his scoresare:\n",j+1);
for(i=0;i<4;i++)
printf("%5.1f",*(*(p+j)+i));
printf("\n");
}
}
}

在这里插入图片描述

8.4通过指针引用字符串

8.4.1 字符串的引用方式

想引用一个字符串,在咱们之前学的;
1)用字符数组存放一个字符串,可以通过数组名和下标引用字符串中的一个字符,也可以数组名和格式声明“%s”输出该字符串;

/*定义一个字符数组,在其中存放字符串,“I LOVE CHINA !"输出该字符串和第八个字符*/#include <stdio.h>
int main()
{char string[]="i love china!";
printf("%s\n",string);
printf("%c\n",string[7]) ;return 0;
} 

从这串代码,咱们可以看出

调用某一个字符,只要输出某一个数组中某一位即可。
string[7];%c;
调用某一个字符串,输出某一个数组就行;
string ;%s;

在这里插入图片描述
2)通过字符指针变量输出一个字符串,或者一个字符(利用指针&数组知识)

/*定义一个字符数组,在其中存放字符串,“I LOVE CHINA !"输出该字符串和第八个字符*/#include <stdio.h>
int main()
{char *string="i love china!";
printf("%s\n",string);return 0;
} 
/
{char *string="i love china!";这一句电脑是如何执行的,
电脑首先会自动在储存空间内部定义一个数组储存空间,这个数组储存空间用来存放这个
字符串,不论是字母还是空格 ,标点符号都属于字符,然后这些都线性分配储存空间之后,
会在字符数组的最后一位放一个\0,作为字符结束标识符;
此时此步骤可以拆分为两步骤:
char *string;
string="i love china!";
这句话意思就是定义了一个指针变量,他的基类型是字符型;
然后之前电脑自动分配的数组第一个元素的地址分配给string;
printf("%s\n",string);
这句话就是输出的时候string是字符串的第一个元素的地址,
然后应为输出的类型又是%s所以说知道遇到\0为止,输出所有字符;

#include <stdio.h>
int main()
{char *string="i love china!";
printf("%c\n",*string);return 0;
} 
输出的是i,*string的意思是第一个元素的字符,输出他;

在这里插入图片描述在这里插入图片描述

/*将字符串a复制到字符串b,然后输出字符串b*/
#include <stdio.h>
int main()
{char a[]="i am student.",b[20];
int i;
for(i=0;*(a+i)!='\0';i++)
*(b+i)=*(a+i);
*(b+i)='\0';
printf("string a is :%s\n",a);
printf("string b is :");
for(i=0;b[i]!='\0';i++)
printf("%c",b[i]);
printf("\n");
return 0; 
} 
/*将字符串a复制到字符串b,然后输出字符串b*/
#include <stdio.h>
int main()
{char a[]="i am student.",b[20];
char *p1,*p2;
p1=a;p2=b;
for(;*p1!='\0';p1++,p2++)
*p2=*p1;
*p2='\0';
printf("string a is :%s\n",a);
printf("string b is :%s",b);
return 0; 
} 

在这里插入图片描述

8.4.2 字符指针做函数参数

1)用字符数组名作为函数的参数;

/*用函数调用实现字符串的复制*/ 
#include <stdio.h>
int main()
{void copy_string(char from[],char to[]);
char a[]="i am a teacher .";
char b[]="you are a student.";
printf("string a=%s\nstring  b=%s\n",a,b);
printf("copy string a to string b:\n");
copy_string(a,b);
printf("\nstring a=%s\nstring b=%s\n",a,b);
return 0; 
} void copy_string (char from[],char to[]) 
{int i=0;
while(from[i]!='\0')
{to[i]=from[i];i++;}
to[i]='\0';
}
/
用字符数组名做函数参数;
首先咱们看看这串代码,我们定义了一个函数,这个函数的功能是将字符串1和字符串2相互
之间互换,而咱们是怎么调用这个函数的。你看;
void copy_string(char from[],char to[]);这是函数的形参,定义了一个字符型的
数组,而电脑在编译他的时候,把from[]转化成了*form,意思就是指向某一个地址;
copy_string(a,b);这个函数定义的实参是a,b;此时实参向形参传递了一个地址;
此时形参里面的地址就是a提供的;而a作为实参是a数组数组名,他向形参传递的是
第一个元素的地址;
再看;
{int i=0;
while(from[i]!='\0')
{to[i]=from[i];i++;}
to[i]='\0';
}
这个定义的函数的函数体,在这个函数体里面,我使用到了from[i]这个i的基准就是
第一个元素提供给的地址;这样就链接起来了;

在这里插入图片描述
2)用字符型指针变量作实参

/*用函数调用实现字符串的复制*/ 
#include <stdio.h>
int main()
{void copy_string(char from[],char to[]);
char a[]="i am a teacher .";
char b[]="you are a student.";
char *from=a,*to=b; 
printf("string a=%s\nstring  b=%s\n",a,b);
printf("copy string a to string b:\n");
copy_string(from,to);
printf("\nstring a=%s\nstring b=%s\n",a,b);
return 0; 
} void copy_string (char from[],char to[])
{int i=0;
while(from[i]!='\0')
{to[i]=from[i];i++;}
to[i]='\0';
} 
/
在这个函数里面我与上面的不同唯有定义了,char *from=a,*to=b; 我定义了两个指针变量;然后就是我不同数组的第一个元素的地址赋值给了指针变量,辞职from 也代表数组a的第一个元素的地址;    

在这里插入图片描述3)用字符指针变量作形参和实参

/*用函数调用实现字符串的复制*/ 
#include <stdio.h>
int main()
{void copy_string(char from[],char to[]);
char *a="i am a teacher .";
char b[]="you are a student.";
char *p=b; 
printf("string a=%s\nstring  b=%s\n",a,b);
printf("copy string a to string b:\n");
copy_string(a,p);
printf("\nstring a=%s\nstring b=%s\n",a,b);
return 0; 
} void copy_string (char *from,char *to)
{
for(;*from!='\0';from++,to++)
{*to=*from;}
*to='\0';
}

与之前一样;*from=form[],一个意思;

在这里插入图片描述
所以总结下来就有一下几种类型;多余的不阐述;
在这里插入图片描述

8.4.3 使用字符指针变量和字符数组的比较

1)字符数组每一个储存空间存放的都是字符元素;而字符指针变量只能储存一个元素,而且只能储存地址;

char a[];
a[]="i am a student!";这个意思是把每一个元素都赋值再给数组;
char *a;
*a="i am a student!";这个意思是电脑先定义一个数组,然后把数组中的第一个元素的
地址给这个变量;

2)可以对指针变量名去赋值,但是不能对数组名去赋值;

char *a;
a="i am a student!";这个意思是电脑先定义一个数组,然后把数组中的第一个元素的
地址给这个变量;
char a[];
a="i am a student!";这是不合法的,数组名是不适合赋值的;

3)初始化的含义不同;

char a[]="i am a student!";这句话的意思是把元素里面的元素一个个赋值;
char *a="i am a student!";这句话的意思是把该数组的第一个元素的
地址赋值给这个指针变量

4)储存单元分配不同

对于指针的储存单元分配一个基类型字节;
但是对于数组而言他是分配若干基类型字节,看数组元素的个数;
对于指针变量,我电脑会随机分配一个储存单元,然后如果你没有对指针变量进行初始化
那么他不代表里面就没有地址,这个地址是随机的,所以说当你使用这个随机地址的时候,会
出现警告,造成非常严重的错误;

5)指针变量的值是可以改变的,而数组名代表的是一个固定的地址数值(数组首元素的地址);
6)引用数组元素

对于数组本身而言,引用数组元素的方法一般就是a[1]
而a[1]电脑是无法识别的,它会被编译成*(a+1)
所以说a[1]=*(a+1)均可以;
同理,如果定义了字符指针变量P,并且使他指向数组a的首元素,则可以用指针
变量带下标的形式引用数组元素p[5],同样,可以用地址法引用数组元素*(p+5)
即p[5]=*(p+5)

??7)字符数组中各个元素的数值是可以改变的,但字符指针变量指向的字符串常量中的内容是不可以被取代的(不能对他们再一次赋值);

char a[]={"i love cina!"};
char *b="house";
a[2]='r';
b[2]='r';//非法,字符串常量不能被改变;
首先得解释一下什么是b[2],b[2]相当于 *(b+2);
为啥'r'不能赋值给b[2];

8)用指针变量指向一个格式字符串,可以用它代替printf函数的格式字符串

format="a=%d,b=%f\n";
printf(format,a,b);
或者用字符数组也可以
cahr format[]="a=%d,b=%f\n";
printf(format,a,b);
看你怎么解读printf ;printf是一个函数
那么这个就是直接调用;不同逗号都是函数实参;
但是format是地址,是地址在这儿,那么说明原本"........."也只是提供一个地址;
电脑编译时王往函数体内送的只是一个地址。

8.5指向函数的指针

8.5.1 什么是函数指针

在程序中定义了一个函数,电脑编译的时候,电脑会给函数定义一个储存空间,而这个储存空间的起始地址,就是这个函数的指针。
可以定义一个指针变量,用来存放某一个函数的起始地址,这意味着此时指针变量通过该地址指向该函数。

8.5.2 用函数指针变量调用函数

举个例子。
通过函数名调用

/*用函数求整数a和b之间的大者*/
/*通过函数名调用*/
#include <stdio.h>
int main()
{int max(int ,int );
int a,b,c;
printf("please enter a and b\n");
scanf("%d,%d",&a,&b);
c=max(a,b);
printf("a=%d\nb=%d\nmax=%d\n",a,b,c);
return 0;
}
int max(int x,int y)
{int z;
if(x>y) z=x;
else    z=y;
return(z);
}

通过指针变量引用函数

#include <stdio.h>
int main()
{int max(int ,int );
int (*p)(int,int);
int a,b,c;
p=max;
printf("please enter a and b\n");
scanf("%d,%d",&a,&b);
c=(*p)(a,b);
printf("a=%d\nb=%d\nmax=%d\n",a,b,c);
return 0;
}
int max(int x,int y)
{int z;
if(x>y) z=x;
else    z=y;
return(z);
}

在这里插入图片描述

8.5.3 怎样定义和使用指向函数的指针变量

通过上面的例子,咱们学会如何定义一个指针变量指向函数。

类型名指针变量名)(函数形式参数系列)

比如

int(*p)(int,int);

系列之间用逗号隔开;类型名是指函数返回值的类型;括号内是形参的类型;一旦定义了这类型,说明该指针变量只能被该类型的函数赋值;这里解释一下为什么要加括号,首先就是括号有优先级*p必须要有括号,否则就是

int *p(int,int);

定义了一个指针形式函数;p是指针变量名;也是指针变量;可以用来储存地址;只能够储存一个地址;储存空间有限

p=max;

max的不仅仅是函数名,还代表该函数的入口地址;还有就是怎么调用函数的时候怎么使用指针变量,

c=(*p)(b,c);

首先括号是要加的,不加更与优先级把指针函数的返回值赋值给c;这句话的意思是指向p内地址的函数,把实参b,c带入函数体;然后把返回值赋值给c;

通过以上咱们可以总结出用指针变量调用函数的时候,指针变量可以调用不同函数,与前面的数组指针变量相比,函数指针指针变量没有运算这一回事;没有意义;

/*输入两个整数a,b,然后让用户选则1和2,选1时候调用max函数,输
出两者之间较大的数值,
选择2得时候调用min函数,输出两者之间较小的数值*/ 
#include <stdio.h>
int main()
{int max(int x,int y);
int min(int x,int y); 
int (*p)(int,int);
int a,b,c,n;
p=max;
printf("please enter a and b\n");
scanf("%d,%d",&a,&b);printf("please choose 1 or 2:");
scanf("%d",&n);
if(n==1)
{
p=max;
c=(*p)(a,b);
}
else
{p=min;
c=(*p)(a,b);} printf("a=%d\nb=%d\nmax=%d\n",a,b,c);
return 0;
}
int max(int x,int y)
{int z;
if(x>y) z=x;
else    z=y;
return(z);
}
int min(int x,int y)
{int z;
if(x<y) z=x;
else    z=y;
return(z);
}

在这里插入图片描述

8.5.4 用指向函数的指针作函数变量

指向函数的指针变量的一个重要用途是把函数的地址作为函数参数传递到其他参数。也就是说,实参是地址,而形参是指向函数的指针变量。实参把地址通过1值传递传递给形参,这样两个指针变量就临时储存了两个函数的入口地址,这样就等价于两个指针变量指向了两个函数。比如

c=fun(f1,f2);//f1,f2也是两个函数的地址。
void fun (int(*x1)(int),int(*x2)(int,int));
{int a,b,i=3;j=5;
a=(*x1)(i);
b=(*x2)(i,j);
}

看个例题

/*有俩个整数a,b,由用户输入1,2或者3.如输入1,
程序就会给出a,b中间较大者,输入2,
就会给出a,b之间较小者,输入3,则会给出两者之和*/ 
#include <stdio.h>
int main()
{int fun(int x,int y,int(*p)(int,int));
int max(int,int);
int min(int,int); 
int add(int,int);
int a=34,b=-21,n;
printf("please choose 1,2,3:");
scanf("%d",&n);
if(n==1) fun(a,b,max);
else if(n==2) fun(a,b,min);
else if(n==3) fun(a,b,add);
return 0;
}
int fun(int x,int y,int(*p)(int,int))
{int result;
result=(*p)(x,y);
printf("%d\n",result);
}int max(int x,int y)
{int z;
if(x>y) z=x;
else z=y;
printf("max=");
return z;
}int min(int x,int y)
{int z;
if(x<y) z=x;
else z=y;
printf("min=");
return z;
}int add(int x,int y)
{int z;
z=x+y;
printf("sum=");
return z;
}

在这里插入图片描述

8.6 返回指针值的函数

咱们学了函数与指针,那么咱们有没有一种可能就是把函数与指针联系起来就是,有一个返回指针值的函数。所谓指针值就是地址。返回一个地址。所以能返回指针值得函数称之为指针函数
那怎么定义指针函数:

类型名 *函数名(参数表列);

注意在这里面函数名就是函数的名字,他的左右是没有括号的;但在参数表列里面有一个括号,括号有优先级别所以说,电脑就直接能判断名字所代表的是函数名了;那么在前面再加一个*意思就是指针函数。

int (*p)(int x,int y);//意思是定义了一个指向函数的指针变量;
int *p(int x,int y);//定义了一个能返回指针数值的指针变量;
/*有a个学生,每个学生有b门课的成绩。要求在用户输入学生序号以后,能输出
该学生的全部成绩*/ 
#include <stdio.h>
int main ()
{float score[][4]={{60,70,80,90},{56,89,67,88},{34,78,90,66}};
float *search(float(*pointer)[4],int n);//这段比较难理解,形参1的意思是定义了一个
//含有四个元素的一维数组。而这个pointer指向这个一维数组整个整体的地址。
float *p;//定义的是一个指向某变量的指针。
int i,k;
printf("enter the number of student:");
scanf("%d",&k);
printf("the scores of NO.%d are :\n",k);
p=search(score,k);
for(i=0;i<4;i++)
printf("%5.2f\t",*(p+i));
printf("\n");
return 0;
}float *search(float (*pointer)[4],int n)
{
float *pt;
pt=*(pointer+n);//pointer+n的意思是同样第二行....第n行的整体开头的地址。
return(pt);} 

在这里插入图片描述
区分这三者之间的区别;

float *p;定义了一个指针变量;指向任意float型变量;
float (*pointer)[4];定义了一个指针变量,指向含有四个元素的一维数组;
float *search(float(*pointer)[4],int n); 定义了一个指针函数 ,能返回指针值;
float*score)(int x,int y); 定义了一个指针变量,指向了函数;

这段话的意思是我定义了一个二维数组,我现在把二维数组的第一行的地址给函数,函数把行地址转化为列地址然后返回出来,然后此时地址是具体某一个数得地址在前面再加*就是输出该数值;
我们把这个例子改一改;

/*有a个学生,每个学生有b门课的成绩。要求在用户输入学生序号以后
,找出其中不合格的课程的学生及其学生号码*/ 
#include <stdio.h>
int main ()
{
float score[][4]={{60,70,80,90},{56,89,67,88},{34,78,90,66}};
float *search(float(*pointer)[4]);
float *p;
int i,j;
for(i=0;i<3;i++)
{p=search(score+i);
if(p==*(score+i))
{printf("No.%d score:",i);
for(j=0;j<4;j++)
printf("%5.2f",*(p+j));
printf("\n"); 
}
}
return 0;
}float *search(float (*pointer)[4])
{int i=0;float *pt;pt=NULL;for(;i<4;i++)if(*(*pointer+i)<60)pt=*pointer;return (pt);} 

![在这里插入图片描述](https://img-blog.csdnimg.cn/20191220194151585.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg0MDA4Nw==,size_16,color_FFFFFF,t_70

8.7指针数组和多维数组

8.7.1什么是指针数组

什么是指针数组,就是说一个数组有若干个元素,若干个储存空间,这些个元素都是一个个储存地址,所以说每一个元素都是指针变量。具有指向的功能。那么指针变量有什么用?加入有若干个字符串。很多,你想给这些字符串进行排序,那么你可以定义一个指针数组,只要改变指针数组的地址,这样输出的时候就能改变字符串的顺序。如果说按照传统方法,你使用是会定义一个二维数组,初始化。首先定义二维数组你肯定得选最长的列数作为二维数组的列数。这样会浪费很多的储存单元,再者说如果你想调换它们之间的顺序的话。你得重新初始化一下,这样会很麻烦,如果使用指针变量,让每个字符串对应一个指针变量,然后这些指针变量组成一个指针数组,如果能达到同样的效果,如果说你想调换它们之间的顺序,你可以调换指针数组之间的地址就可以了。就会很方便。
说来这么多,我们来看一看怎么定义一个数组指针。

类型名 *数组名[数组长度];
比如

int *p[4];这句话的意思是定义了一个指针数组,包含四个指针变量;
int (*p)[4];定义了一个指针变量,指向一个包含四个元素的一维数组;

*p有无括号很重要,如果没加括号,像第一个,电脑会首先识别括号[]内的内容,他的优先级大。这样电脑就会知道p是一个数组,又有指针型符号,所以是指针型数组。括号的顺序是自左向右;对于第二个,所以说先识别(*p),电脑知道了,他是一个指针变量。然后是什么指针变量呢?后面告诉你了,是一个一维数组,包含四个元素的指针变量。

咱们看一个例子;

/*将若干字符串按照字母顺序输出(由小到大)输出*/
#include <stdio.h>
#include <string.h>
int main()
{void sort(char *name[],int n);void print(char *name[],int n);char *name[]={"Follow me","BASIC","great wall","FORTRAN","Computer design"};int n=5;sort(name,n);print(name,n);return 0;} void sort(char *name[],int n){char *temp;int i,j,k;for(i=0;i<n-1;i++){	k=i;for(j=i+1;j<n;j++)if(strcmp(name[k],name[j])>0) k=j; //对于strcmp函数字符串比较函数,如果大于,函数值为正值,如果是小于,则函数值为负数;// 如果是等于,则函数值是0;具体看数组字符串函数那儿;if(k!=i){	temp=name[i];name[i]=name[k];name[k]=temp; // 指向互换}}}void print(char *name[],int n){int i=0;char *p;p=name[0];while(i<n){p=*(name+i++);//这句话的意思是先执行*(name+i),//  所以说就是先name+i的意思是第二个元素的地址,*(name+i)的意思是对应的某个字符串的开头地址。然后赋值给p,再i++;printf("%s\n",p);}} //换一种写法print void print (char *name[],int n){int i;for(i=0;i<n;i++)printf("%s\n",name[i]);} 

8.7.2指向指针数据的指针

前面咱们学了,指针变量的指向,可以有普通变量,数组,函数。这儿咱们说指针还可以指向指针自己。上面咱们说对于一个指针数组而言,里面各个元素都储存的是地址,每一个单独的单元都是一个单独的指针。

name[0];-->a1
name[1];-->a2
name[2];-->a3
...

所以说这三个都是指针,那么我能不能再定义一个指针p,就是指向他们。

int *a;
int a1;
a=&a1;那么说a指向a1里面储存的数值 3or4or5;
指向某一整数型数据的指针变量;
char *(*p);
char *name[4];
p=name;那么说p指向name储存的数值,&1or&2or&3;称为指向指针的指针变量;
char *p
char name[4];
p=name;那么说指针变量指向的是name中储存的数值,'q' or 'w' or 'e';
称为指向数组的指针变量;
int *sum(int x,int y); 定义一个函数,能返回函数值是指针值;
int (*sum)(int x,int y);定义一个指针变量指向函数,比如(*sum)(1,2);储存返回指针值的变量;

所以说所有指针类型都是储存地址,但指向不同,它指向是指针。就是说指向的储存单元里面的储存内容还是地址;这就是指向指针的指针变量;
那么我们怎么定义一个指针变量指向指针:

类型名 *(*指针名)

比如,

char *(*p);

先识别括号内(*p),是一个指针变量,这个指针变量指向指针变量,然后就是给与了char *,就是说p指向的是char型数据。

char *p;
char *(*p);
p;指向的是char型数据的指针变量;
*p;指向的是p这个指针变量;

注意

char **p;char *(*p);等价;

看个例子:

/*使用指向指针数据的指针变量*/
#include <stdio.h>
int main()
{char *name[]={"FOLLOW ME","BASIC","GREAT WALL","FORTRAN","COMPUTER"};char **p;int i;for(i=0;i<5;i++){p=name+i;printf("%s\n",*p);} return 0; 
} 

在这里插入图片描述

/*有一个指针数组,其元素分别指向一个整型数组的元素,用指向指针数据的指针变量,输出整形数组的个元素的数值。*/
#include <stdio.h>
int main()
{int a[5]={1,3,5,7,9};int *num[5]={&a[0],&a[1],&a[2],&a[3],&a[4]};int **p,i;p=num;for(i=0;i<5;i++){printf("%d\n",**p);p++;}printf("\n");return 0;
} 

在这里插入图片描述
指针是属于间接访问;那么指针指向指针属于二级间接访问,那么同理说有二级就有三级,四级等多级。不过越多越麻烦好理解,也容易出错。如下图。
在这里插入图片描述

8.7.3指针数组作main函数的形参

一般main函数括号内都是空的,里面没有形参,也就是说操作系统不需要给主函数提供实参。
通常main函数与其他函数构成一个文件模块,具有一个文件名字。在编译和连接之后,得到一个exe的可执行文件。然后用户执行这个exe,操作系统就会调用main函数,然后main函数就会调用其他函数,从而得到相应的结果。

int main()int main(void);

但是有的时候,main函数也会具有形式参数,比如。

int main(int argc,char *argv[]);

前者argv的意思是参数个数,后者是指针数组。里面每一个指针元素指向一个字符串。
main函数是操作系统调用的,所以说main函数是操作系统提供实参的。

具体看看UNIX系统怎么提供参数的。

首先UNIX系统在exe中如何输入命令行:

命令名 参数1 参数2 参数3(中间按空格隔开)
命令文件名必须要有,而且占据指针数组第一个储存空间,但是它不属于传送到主函数的参数。所以说参数有三个,其中传递到函数中的参数只有两个。但是参数又三个,指针数组中的数值也有三个。 如下图。
在这里插入图片描述

int main(int argc,char *argv[])
{while(argc>1)//argc=3{++argv;//argv指向的是数组第二元素的地址printf("%s\n",argv);--argc;}return 0;
}
这是一个在UNIX系统里面执行的程序。
exe文件框中输入=====================================file1 China Beijing=====================================最后输出:============ChinaBeijing============程序改写:int main(int argc,char *argv[]){while (argv-->1){printf("%s\n",*++argv);}}

echo 命令:即将echo后面的各个参数在同一行输出。

#include <stdio.h>
int main(int argc,char *argv[])
{while(--argc>0)printf("%s%c",*++argv,(argc>1)?'':'\n');return 0;
}
exe 执行文件显示框输入:
==================echo Computer and c language==================
显示屏输出
============Computer and language============
程序可以改写:
#include <stdio.h>
int main(int argc,char *argv[])
{int i;for(i=1;i<argc;i++)printf("%s%c",argv[i],(i<argc-1)?'':'\n');return 0;
}

8.8 动态内存分配与指针变量

8.8.1什么是内存的动态分配

前面咱们学过了全局变量还有局部变量,电脑有动态储存区,也有静态储存区域;
全局变量放置在静态储存区域,局部变量储存在动态储存区;比如函数,在定义形参的时候,建立一个储存区域,然后函数执行结束的时候,区域自行解散。
这里我们强调一个动态分配区域这是一个非常自由的区域,想用的时候就用,想解散的时候就自行解散。可以说在静态储存区的是要事先声明的,但是再动态分配区域是不需要事先声明的,直接用就完了。
所以说它不能通过变量名字或者数组名字去引用这些数据,只能通过指针来使用
这里推出两个概念:


C/c++程序经过编译连接后形成的二进制映像文件,这文件包含:
栈,堆,数据段(只读数据段,已经初始化读写数据段,未初始化数据段即BBS)和代码段组成.
在这里插入图片描述
1.栈区(stack):
由编译器自动分配释放,存放函数的参数值,局部变量等值。其操作方式类似于数据结构中的栈。
2.堆区(heap):
堆允许程序在运行时动态地申请某个大小的内存。
一般由程序员分配释放,若程序员不释放,则可能会引起内存泄漏。
注堆和数据结构中的堆栈不一样,其类是与链表。
3.程序代码区:存放函数体的二进制代码。
所有的语句编译后会生成CPU指令存储在代码区.
4.数据段:由三部分组成。


栈:动态储存区域

堆:动态分配区域

8.8.2怎样建立内存的动态分配

提供这些的动态储存空间的方法,一般是malloc,calloc,free,realloc;调用这些函数要使用头文件+#include <stdlib.h>;

1.malloc

函数原型:
void *malloc(unsigned int size);
这个定义的是一个指针函数,void 的意思是返回的地址所指向的void.
就是说无任何类型。
返回的是所分配区域的第一个字节的地址,是一个抽象的概念。
其中形参是一个无符号整数。size就是你需要的常数
调用:malloc(100);如果不能成功的执行,比如储存空间不足,那么返回空指针NULLexample :L.data =(ElemType*)malloc(sizeof(ElemType)*InitSize);//动态扩展内存。

2.calloc

 函数原型:void *calloc(unsigned n,unsigned size);这个定义是一个指针函数,void的意思是返回一个无任何类型的地址。返回的地址是所分配区域的第一个字节。是一个抽象的概念。意思是分配n个长度为size的连续空间。这个空间一般比较大,可以为一个数组。调用:p=calloc(50,4);分配不成功,返回NULL;

3.free

 函数原型:void free(void *p);
释放指针变量p所指向的动态空间。p是最近一次调用calloc,malloc的返回值。
free函数无返回值。
调用:free(p);

4.realloc

void *realloc(void *p,unsigned int size);如果你已经使用了colloc malloc 函数获得了动态空间,想改变其(size)。可以使用realloc函数重新分配。调用:realloc(p,50);  //将p所指向动态储存空间的长度改为50个字节。
同样返回一个地址,所分配字节区域第一个地址。如果分配不成功,返回NULL

C99以前是没有void 型的,其mailloc ,colloc 一般都是char 型 ,如果想建议一个动态的整型需要强制类型转换;

char *malloc(unsigned int size);
pt=(int *)malloc(100);

8.8.3void的指针类型

定义一个void 类型的指针

void *p1;

这个指针意思是不指向任何值的。是一个空的类型;

p1=(void *)&a;
也可以写
p1=&a;编译系统会自动转换。

p1具有a的地址,但是不具备指向a中的数值的能力。也就是说不具备指向功能。

/*建立一个动态数组,输入五个学生的成绩,另外用一个函数,检查其中有没有低于60,输出不及格的成绩*/
#include <stdio.h>
#include <stdlib.h>
int main()
{void check(int *);int *p1,i;p1=(int *)malloc(5*sizeof(int));for (i=0;i<5;i++);scanf("%d",p1+i);check (p1);return 0;
} void check(int *p)
{int i;printf("they are fail:");for(i=0;i<5;i++)if(p[i]<60)printf("%d",p[i]);printf("\n"); 
}