C语言指针、数组与函数

一、指针

指针变量也是一种变量,用来记录地址数据的变量,声明时应该加*,*也称为解引符号,&为取址符号,格式为:数据类型*指针名称=指向的地址;例如

int a=5;
int*p=&a//把a的地址赋给指针变量p,也就是p指向a的地址
printf("%d.....%d",a,*p);//结果是5   5,*代表去除p指向地址里的数值
如果是char*p;是p是指向char类型变量的指针

 注:指针还可以来存储字符串,但不能存储字符

char*p='a';//error,指针是存储地址,并不能存储字符常量
char*p="msg";//ok,首先msg在常量区申请了空间存放了字符串msg,并在结尾加了'\0',把字符串首地址返 
             //回给p

上述说的是一级指针,指向的是变量的地址,还有二级指针,指向指针的指针,存的实际上是一级指针的地址,经常用在二维数组中。

格式:  数据类型**指针名称=指针的地址(例如,上述p指向a的地址,int**p1=&p,p1指向指针p的地址)

                                  

指针运算也可以进行加减,自加自减,加1即是加了一个数据类型的大小,减一即是减了一个数据类型的大小。int类型相当于移动4个字节,char类型相当于移动1个字节。

二、指针与数组

一维数组和指针

一维数组的名称是数组的首地址,例如char arr[5];  arr即是数组的首地址,这时就可以申请一个指向char类型的指针变量指向arr,也就指向了数组的首地址,但arr是常量,是不可能更改的,指针是变量,可以用来遍历数组;

          

char*pr=arr;当不改变arr时,他的作用等同于pr,pr[1]就等同于arr[1],以此类推

但pr++、pr--,pr=pr+1;这些操作是可以的,但arr不行,它是一个常量。指针也可以比较大小

pr+1>pr;这个表达式是成立的;

经常会使用while和for进行一个数组遍历,例如

int arr[5]={0};
int *pr=arr;
int *pr1=pr+4;
/*for(int i=0;i<=4;i++){
    arr[i]=5;
}//会循环五次,把所有的元素赋值为5
*/
while(pr<=pr1){
    *pr=5;
     pr++;
}//同样会循环五次,把所有的元素赋值为5

二维数组和指针

二维数组的名称代表它第一行的行地址;例如

char arr[2][3]={1,2,3,4,5,6};
//arr代表这个数组的第一行行地址,此时arr+1相当于第二行的行地址
//想拿到第一行第一个元素的地址使用*解引,*(arr+n)+n即是第n+1行第n+1个元素的地址
//总结即是*(*(arr+n)+n)就是第n+1行第n+1个元素,注意不要越界
//例如*(*(arr+1)+1)就是第2行第2列的元素也就是5;

数组指针 

这时想要指向二维数组,那就需要使用数组指针了,因为普通的指针每移动依次移动的是一个数据类型的大小,但是arr+1移动的确实一行的数据类型的大小,直接从上一行移动到下一行了,那么这就造成了不同步,因此使用数组指针

格式:数据类型(*指针数组名)[数组列数];   例如:

char(*pr)[3]=arr;//此时pr就可以当做arr用了,不同的是pr作为指针可以进行自加自减等赋值操作,它是一个变量
++p;//这时p指向了第二行的行地址

指针数组

实质是数组,用来存放指针的数组

格式:存储类型 * 指针数组名[数组行数],例如int a[2][3];  int *arr[2]={a[0],a[1]};//把二维数组中第一行和第二行的第一个元素地址放入指针数组中;这时arr[0]就是a[0],arr[1]就是a[1];

结构体指针

用来指向结构体存储区的指针

typedef struct person{
        int age;
        float height;
        char name[10];
}per_t;
per_t pern;
per_t *p=&pern;
//可以用*p这个结构体指针来访问pern这个结构体的成员变量了
p->age;//访问age
p->height;//访问height
p->name;//访问name

结构体数组

存放相同类型结构体的数组,例如

struct student{
    int id;
}stu[5];
这就申请了一个名叫stu的数组,有五个元素,每个元素存储一个结构体的地址
大小就是结构体类型的大小*元素个数;

三、函数与指针

函数的三要素:功能、参数、返回值

一个函数往往要实现某一种或几种功能,例如我们经常用的主函数,它应该是

int main(int argc,const char* argv[]){}

main前面的int是它的返回值类型,说明了它的返回值是int型

argc代表的是我们执行函数的时候传了几个参数,例如我们编译执行函数是会执行./a.out,那么argc就是1,./a.out存放在argv[0]中;如果还传了别的参数,那么argc就会增加,下一个参数会存在argv[1]中,以此类推

argc和argv[]就是main函数的参数

多函数程序执行

在实际编程工作中,不会把所有的函数都放在main函数中,会将各个功能函数分别编写,有利于维护,那么当多函数程序执行时​,例如​​​​​​

A函数先干了一部分工作,这时需要B函数来做下一部分工作,那么A就调用B函数来做这部分工作,B函数执行完必后,A要继续完成下面的工作。A叫做调用函数,B叫做被调用函数

 主函数调用func2,然后func2调用func1,func1执行完,交还给func2继续执行,func2执行完交还给主函数继续执行,但是在函数内部定义的变量只能在函数内部使用,要注意变量的作用域和生命周期,局部变量多次执行存储区不同

定义变量的时候可以重名,全局变量程序执行期间所有函数都可以使用,但是函数内部优先使用自己的局部变量,例如

#include<stdio.h>
int val=3;
int read(void){
        int val=2;
        printf("val:%d\n",val);//会优先使用局部变量打印2,而不会打印3
        printf("请输入一个数:");:
        scanf("%d",&val);//输入5
        return val;
}
int main(void){
        int val=read();
        printf("val:%d\n",val);
        return 0;
}//会输出5

编写函数时,如果函数被调用函数写在调用函数下面,应该先声明一下,告知编译器下面有这个函数,才能编译通过

如果read()函数写在主函数下面,那么要头文件下面声明read函数,例如int read();即可

数据传递放在被调用函数的存储区,只能从被调用函数向调用函数传递一个数据,叫做被调用函数的返回值,只能在最后一步传递返回值

调用函数得到返回值或立即使用,或者存放在别的存储空间中,无返回值,函数名称前用void类型

不可以用数组存放返回值

可以从调用函数向被调用函数传递多个数据,类型可以不同,被调用函数要为传递过来的数提供一个专用的存储区,代表这些存储区的变量应该声明在函数名称后的小括号中,叫做形式参数,类型不可忽略。

被调用函数可以把形参当做变量使用,调用函数提供的参数叫做实际参数,也叫实参。例如

#include<stdio.h>
void add(int val,int val1){//val、val1是形参
        printf("%d\n",val+val1);    
}
void min(int val,int val1){
        printf("%d\n",val-val1);
}
int main(void){
        add(8,6);//14,8和6即是实参
        min(8,6);//2
        return 0;
}

函数指针

函数也有地址,函数名称可以用来标示函数地址,函数指针可以记录函数地址

格式   返回值类型(*函数指针名)(参数类型)

例如int (*pfunc)(int,int)=add;那么add函数的地址存储在pfunc的函数指针中,pfunc(3,5)和add(3,5)结果相同

函数指针数组

存放多个函数入口地址的数组叫做函数指针数组

格式:返回值类型(*指针数组名[元素个数])(参数类型)

例如 int(*arr[2])(int,int)={add,min};

add函数的入口地址被存入arr[0]中,min函数的入口地址被存入arr[1]中;

add可以用a[0]标示,add(3,5)和a[0](3,5)结果相同

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值