C语言中指针超详细讲解(1)

本文详细介绍了指针的概念、类型、运算,包括字符指针、数组指针、二维数组的使用以及指针在函数传参中的角色,帮助读者理解指针在编程中的核心作用。
摘要由CSDN通过智能技术生成

接下来我会为大家带来指针的超详细讲解。涵盖了指针的所有相关知识,内容比较多大家慢慢看。

我们先为大家详解一下指针这个概念

指针    指针==地址

1.指针变量就是个变量,用来存放地址,地址的唯一标识就是一块内存空间。

2.指针的大小是固定的4/8个字节(32位平台、64为平台)。

3.指针是有类型的,指针的类型决定了指针的+-正数的步长,指针解引用操作时的权限。

4.指针是可以进行运算的。

我们今天开始一点一点的学习与认识。

1.字符指针

 在指针的类型中我们知道有一种指针类型为字符指针 char*;

代码演示

int main()
{

   char ch = 'w';
   char *pc = &ch;
        *pc = 'w';
   return 0;
}

现在我们有新的写法

int main()
{
   char ch ='w';
   char*pc=&ch;
   
   char*p="abcdef";
   还有另外两种写法"abcdef"可以替换为下面的写法
         //[abcdef\0]
         //char arr[]="abcdef";
        return 0;
}

我们拿出   char *p= "abcdef"; 来分析。我们可以写出一个常量字符串"abcdef",把字符串的首元素‘a’的地址赋给p.    关键点拨:当我们想要打印字符串时我们可以直接使用printf函数.

printf("%s\n",p);

因为p中放的就是字符串的起始位置。

有了上述知识我们来看一道面试题

程序的运行结果究竟是什么呢?

可是这是为什么呢?接下来我为大家详细讲解一下。

就是str1和str2,各自开辟了一段空间存放"hello bit."

那么我们就很好理解了,两个不同的空间的首元素地址当然不想同啊。

然而在第二个前面加了Const是不可修改的,所以str3,与str4,指的是同一个地址

2.指针数组

指针数组是数组

例如

字符数组  —  存放字符的数组

整形数组  —  存放整形的数组

指针数组  —  存放指针的数组,存放在数组中的元素都是指正类型的

我们简单来看一下作用(使用指针数组来模拟一个二维数组)

int main()
{
   //定义三个一维数组
   int arr1[]={ 1,2,3,4,5 };
   int arr2[]={ 2,3,4,5,6 };
   int arr3[]={ 3,4,5,6,7 };
   //如何这三个一维数组变成二维数组的一行呢?
   //由于上述三个数组都是int类型的所以arr也应为int型的
    int* arr[]={ arr1, arr2, arr3 };
   return 0;
}
   

我们画图不难得出一种指向关系

那么这样arr1作为一个整体存放入arr中那么其首元素1,就是在arr中下标为0。

则有

那么该如何实现数组的访问呢?

我们可以思考是否可以通过下标来访问,我们使用循环先访问数组,再访问数组的内容。

接下来为大家展示。

int i=0;
int j=0;
for(i=0;i<3;i++)
  {
  for(j=0;j<5;j++)
{
  arr[i][j];
}
  }

3.数组指针

在讲解之前先来温习一下数组名

数组名是数组首元素地址

存在两个列外

1.sizeof(数组名),这里的数组名表示的是整个数组,sizeof(数组名)计算的是整个数组的大小,单位是字节。

2.&数组名,这里的数组名表示整个数组,取出的是数组的地址。

指针数组---是数组,是存放指针的数组

数组指针--是指针

字符指针--指向字符的指针

整型指针--指向整型的指针

浮点型的指针--指向浮点型的指针

数组指针--指向数组的指针

接下来进入正题

int main()
{
 //int*p
 int arr[10]={0};
 int(*p)[10]=&arr;
 //p是用来存放数组地址的,p是数组指针
 return 0;
}

我们来思考一个问题,数组指针到底有什么用呢?

1.用来访问数组

int main()
{
  int arr[10]={  1,2,3,4,5,6,7,8,9,10 };
  int *p=arr;
  int i=0;
  for(i=0;i<10;i++)
  {
    printf("%d ", p[i]);
  }
    return ;
 }

2.二维数组的使用

当我们想打印出一个二维数组时,我们自定义一个函数print来实现
          形参也是二维数组的形式
void print(int arr[3][5],int r,int c)
{
   int i=0;
   for(i=0;i<3;i++)
  {
     int j=0;
     for(j=0;j<5;j++)
     { 
       printf("%d", arr[i][j]);
     }
       printf("\n");
     }
}
 


int main()
{
  int arr[3][6]={ {1,2,3,4,5} , {2,3,4,5,6} , {3,4,5,6,7} }
  print(arr,3,5);      二维数组的传参
  return 0;
}

以上是我们最简单二维数组的访问,那么我们该如何使用指针来操作呢?

关键点拨:二维数组的数组名是首元素的地址,首元素的地址是第一行的数组。

在二维数组中的首元素是一维数组如上图所示。

在第二个代码中我们可以观察到  int(*p)[5],我来为大家解释一下,其含义是什么意思?

我们可以理解为数组名传参传的是首元素地址(上面讲到二维数组的首元素是一维数组,{1,2,3,4,5,}),那么我们就可以使用一个指针(*p)来指向这个一维数组(这个一维数组有五个元素)。其中p[i][j]是什么意思? 其实很简单就是  *(p+i)的意思。我们先解引用拿到数组名然后进行访问。

对于上述大家可以会有疑问现在我为大家来解释清楚。

int arr【5】;   arr是一个可以存放5个整形数据的数组

int *parr1【10】;   parr1 是一个数组,数组有10个元素,每个元素的类型都是int*

int (*parr2)【10】;  parr2是一个指针,该指针是指向数组的,指向的数组有10个元素,每个元素的类型是 int.

int (*parr3【10】)【5】;parr3是一个数组是存放数组指针的数组,存放的这个数组指针指向的数组有5个元素,每个元素是int类型。

对于*parr3我们来画图进行理解

存放的指针数组有是个元素,每个元素都指向一个数组。

4.数组参数,指针参数

在写代码的时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢?

4.1 一维数组的传参

先告诉大家关键知识点:数组的传参的本质是,传递了数组首元素的地址。数组传参的形式也可以是指针形式!

在这里我会通过列子为大家展示

假设我们有个数组arr,现在我想把它传给test函数。该如何设计呢?

我设置的是判断,上面的第 2,4,6,8,10,行后面有个OK,大家来判断一下是否可以成功实现。

2.数组传参,形参的部分也是数组,所以2是符合的,因为传参的本质不是数组而是首元素地址。其大小可以省略就是int arr【】可以为空的。

4.由2中解释,【】中的大小可以写,也可以不写不影响其传参。4也是符合的

6.数组名首元素地址是int ,在6中接收的类型也是int类型。故6也符合

8 .实参是指针数组,形参也是指针数组。也符合

10.由于 int *arr2【20】={0};可知,arr2中每个元素都是int* 类型的由于传的是首元素地址那么传的就是 int*  所以把一级指针取出来放入 int **arr(二级指针中)是没有问题的。故10也符合

那么我们继续

4.2二维数组的传参

下述的 1, 2,3,4,5,6,7.指的是OK  1.代表的是第一个OK所在的语句。

 1.由于都是3行5列的数组,传参没有任何问题。

 2. arr[ ][ ]是行不通的,因为二维数组的行可以省略,但是列不能省略。

3.由2可知符合

4.int *arr是整形指针只能接收整形变量但test(arr)不是整形故不符合。

5.传的是二维数组,接收也应是二维数组,故5也行不通。

6.是正确的  上文中的就是使用这个方法

7.二级指针是错误的,二级指针是接收一级指针的地址的。

有了上述知识我们来学习,指针的传参。

4.3一级指针的传参

很简单我们在前面已经学习过了,就是使用指针来接收

 

重要的是我们要思考: 当一个函数的参数部分为一级指针的时候,函数能接收什么参数?

比如  一个函数

void text (int *p)
{
    
}

那么有哪些可以传给它参数呢?  其实只要我们传的参数它可以 接收就行。

整形一级指针函数接收整形的地址

那么我们就可以写出很多例如:

int a=10;
int *ptr=&a;
int arr[5];
   

text(arr);  // 传整形一维数组名
text(&a);   // 传整形变量的地址
text(ptr):  // 传整形指针

4.4二级指针的传参

二级指针传参使用二级指针来接收。

5.函数指针

我们先来类比一下

数组指针 --  指向数组的指针 -- 存放的数组的地址 -- &数组名就是数组的地址。

函数指针 --  指向函数的指针 -- 存放的是函数的地址 -- 怎么得到函数的地址呢? &函数名呢?

我们来验证一下

int Add(int x,int y)
{
  return x+y ;
}
int main()
{ 
  printf("%P\n", &Add);   //我们试着得到Add的地址
  return 0;
}

程序运行结果如下:

我们确实得到了地址可得结论:&函数名可以得到函数的地址。

此时又有一个疑问:数组名数组首元素的地址。那函数名呢?

我们执行程序可以得到

 

 通过上述我们可以总结一下:&函数名就是函数的地址

                                                  函数名也是函数的地址

指针内容非常多,这只是其中一小部分,后续我会为大家发布(2)(3)(4)

请大家及时关注以免错过

谢谢你的阅读。

     

                              

  • 32
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值