【C语言】指针篇-一篇搞定不同类型指针变量-必读指南(3/5)

简介: 【C语言】指针篇-一篇搞定不同类型指针变量-必读指南(3/5)

一、字符指针变量

对于字符和字符串,C语言统一使用char类型来表达式。对此字符指针变量有两种表示方法:

  1. 第一种: char ch='a'; char *p=&ch;
  2. 第二种: const char *pstr="Hellow world";

问题:关于const char *pstr="Hellow world"是将整个字符串放到字符指针里面了吗?

解释:本质是字符串"Hellow world"首字符(H)的地址放到字符指针变量pstr中.

面试题:剑指offer】

int main()
{
char str1[] = "hellow world";
char str2[] = "hellow world";
const char *str3 = "hellow world";
const char *str4 = "hellow world";
if(str1 ==str2)
        printf("str1 and str2 are same\n");
    else
      printf("str1 and str2 are not same\n"); 
if(str3 ==str4)
        printf("str3 and str4 are same\n");
    else  
        printf("str3 and str4 are not same\n");
return 0;
}
结果:
str1 and str2 are not same 
str3 and str4 are same

解释】:

str3str4指向的是一个同一个常量字符串。C/C++会把常量字符串储存到单独的一个内存区域(常量区),当多个指针指向同一个字符串时,实际是指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时就会开辟不同的内存块,更直白说就算将常量字符串从常量区拷贝一份到数组中,那么在数组初始化时就会在栈中开辟不同的内存块。

使用指针初始化的"hello world"是一个常量字符串,str3指向首字符地址,但该地址在于进程的text段,text段可以保存常量还可以执行代码,是不允许可写权限,只有可读、可执行权限(了解即可)

char *p="hellow";
p[1]='d';//*(p+1)='d';//出现段错误

二、数组指针变量(指针数组,这里需要注意偏正)

  • 整形指针变量:int *p(存放的是整形变量的地址,能够指向整形数据的指针)
  • 字符指针变量char *p(存放的是字符或字符串首元素的地址,能够指向字符或者字符串数据的指针)

依次类推

数组指针变量:存放的是数组的地址,能够指向数组的指针变量

那个是数组指针变量?那个是指针数组变量?
int *p1[10];
int (*p2)[10];

:[]的优先级高于*。

  • p1和[]结合形成一个数组,指向数组中int *类型的元素,是指针数组。
  • p2和 *加上了()保证了p2先和 *结合形成一个指针,指向一个大小为10个整形的数组指向一个多大的数组),是数组指针(存放的是数组的地址)

2.1 数组指针的初始化

int (*p) [10] = &arr;
|     |    |
|     |    |
|     |    []:p指向数组的元素个数
|     p:数组指针变量名
int:p指向的数组的元素类型

2.2 二维数组传参的本质

二维数组是由多个一维数组组成的,也是连续存放数据。这样说明:二维数组的每个元素都是一个一维数组,根据数组名是数组首元素的地址这个规则,二维数组的数组名表示是第一行的地址(一维数组的地址)

对此第一行的地址的类型是数组指针类型int(*)[5]。意味着跟一维数组传参本质一样,也是传递地址,传递的是第一行这个一维数组的地址

小总结:二维数组传参,形参的部分可以采用数组或者指针形式

void test1(int nums[][5]);//数组类型
void test2(int (*nums)[5]);//指针类型
int main()
{
    int nums[][5]={{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}};
    test1(nums);
    test2(nums);
    return 0;
}

三、函数指针变量

函数指针变量:存放函数地址的,通过函数的地址来调用函数

问题:那么如何得到函数的地址呢?

void test();
int main()
{
    printf("&test==%p",&test());
    printf("test==%p",test());
    return 0;
}
结果:
&test==00991253
test==00991253

通过输出的结果:函数是有地址的,函数名就是函数的地址,&函数名的方式也可以获得函数的地址

void (*pf1)() = &test;
void (*pf2)() = test;

3.1 函数指针变量初始化

int    (*pf3)        (int x, int y)
 |        |           ------------
 |        |                 |
 |        |     pf3指向函数的参数类型和个数的交代
 |    函数指针变量名
 pf3指向函数的返回类型
    
int (*) (int x, int y) //pf3函数指针变量的类型

函数指针变量的使用(通过函数指针调用指针指向的函数)

int Add(int x,int y)
{
  return x+y;
}
int main()
{
    int (*p)(int x,int y)=Add;//如果需要存放多个函数地址,需要使用到函数指针数组
    printf("%d\n",(*p)(a,b));
    printf("%d\n",p(a,b));
    return 0;
}

说明:p(a,b)(*p)(a,b)效果是相同的,因为函数名本身就是函数指针变量


四、函数指针数组

如果我们需要把多个函数的地址存在数组中,函数名是一个函数指针变量,就需要利用到指针数组和函数配合了

存放函数的地址的指针数组

int (*)()(类型的函数指针):
void (*p[3])(void x,void y)={Add,Sub};
方便理解:
p[] = x;
void (*x)(void x,void y)={Add,Sub};

说明:p先和[]结合,说明p是数组,数组的内容void (*)()类型的函数指针。


五、转移表

函数指针数组的用途:转移表

比如:使用函数指针数组实现计算器

实现函数功能

int add(int a, int b)
{
  return a + b;
}
int sub(int a, int b)
{
  return a - b;
}
int mul(int a, int b)
{
  return a * b;
}
int div(int a, int b)
{
  return a / b;
}
int main()
{
  int x = 0, y = 0;//操作数
  int input = 0;//选择功能
  //前面加个0,方便输入数字得到相对函数功能
  int (*computer[5])(int x,int y) = {0,add,sub,mul,div };
  do
  {
    mune();
    scanf("%d", &input);
    if (0 < input && input <= 4)
    {
      printf("输入两个操作数\n");
      scanf("%d %d", &x, &y);
      int ret = (*computer[input])(x, y);
      printf("结果为%d\n", ret);
    }
    else if (input == 0)
    {
      printf("退出计算机\n");
    }
    else
    {
      printf("非法输入\n");
    }
  } while (input);
  return 0;
}

说明:根据函数指针数组的结构,我们可以通过两个部分,选择数组中函数,并且为调用函数选择函数参数。

缺点:这么好用的东西也有他自己的美中不足,不知道你有没有发现,这些函数的功能的参数部分,返回值类型是一样的,如果需要使用函数指针算组,建议需要实现的函数参数部分和返回值类型保持一致。


六、typedef 关键字

typedef:用于类型重命名的(将复杂的类型进行简单化)(typedef是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换)

语法:typedef 类型(自定义取名)

例子:

typedef int it;
typedef int *  intt;
对于数组指针和函数指针有一些区别
typedef int(*part)[5];//数组指针类型int (*)[5]
typedef int (*part)(int;)//函数指针类型 int (*)(int);

关于typedef相关的知识点,这里只是简单介绍。比如:在使用typedef遇到const对象就可能会出现问题如果大家对typedef这个知识点感兴趣,可以参考这份资料:typedf

这里就简单分享一个typedef遇到const的陷阱

typedef char* Ptr
int compare(const Ptr e1 , const Rtr e2)

说明:typedef它不是简单的字符串替换,先分析const Ptr意味着Ptr整体被const赋予了常量性,那么typedef以后应该是char * const e1保证Ptr指针本身的常量性、不能修改指针本身。


以上就是本篇文章的所有内容,在此感谢大家的观看!这里是店小二C语言笔记,希望对你在学习C语言中有所帮助!

相关文章
|
1天前
|
算法 搜索推荐 C语言
【C语言篇】深入理解指针4(模拟实现qsort函数)
【C语言篇】深入理解指针4(模拟实现qsort函数)
10 2
|
1天前
|
存储 C语言
【C语言篇】深入理解指针3(附转移表源码)
【C语言篇】深入理解指针3(附转移表源码)
9 1
|
1天前
|
Serverless 编译器 C语言
【C语言】指针篇- 深度解析Sizeof和Strlen:热门面试题探究(5/5)
【C语言】指针篇- 深度解析Sizeof和Strlen:热门面试题探究(5/5)
|
1天前
|
搜索推荐 C语言 C++
【C语言】指针篇-精通库中的快速排序算法:巧妙掌握技巧(4/5)
【C语言】指针篇-精通库中的快速排序算法:巧妙掌握技巧(4/5)
|
4月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
1月前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
|
2月前
|
C语言
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)
|
2月前
|
C语言
【C初阶——指针4】鹏哥C语言系列文章,基本语法知识全面讲解——指针(4)
【C初阶——指针4】鹏哥C语言系列文章,基本语法知识全面讲解——指针(4)
|
2月前
|
存储 编译器 C语言
【C初阶——指针3】鹏哥C语言系列文章,基本语法知识全面讲解——指针(3)
【C初阶——指针3】鹏哥C语言系列文章,基本语法知识全面讲解——指针(3)
|
3月前
|
编译器 C语言
【C语言初阶】指针篇—下
【C语言初阶】指针篇—下