指针基础知识点合集3(基础入门到深入理解)

知识特点(学习方向)

上一篇介绍了更深一步的指针,这一篇将涉及 字符指针变量,数组指针变量,⼆维数组传参的本质,函数指针变量,函数指针数组,转移表,assert断言等一些知识点,每篇内容不多很好理解,相信大家看完这几篇之后会对指针的理解有质的飞跃

深入理解未来会继续连更3篇,如果需要可以先关注。

每一个知识点都讲的很细节,已经学明白并掌握第一节指针基础知识点合集1,2(侧边有合集栏)的同学让我们一起继续深一步的学习。

运用类比,希望大家能和前面知识点联系起来,多比较,多研究,祝大家学习愉快。

1.字符指针变量(char*)

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

一般使用:

int main()
{
 char ch = 'w';
 char *pc = &ch;
 *pc = 'w';
 return 0;
}

赋值字符串的形式(思考:是将一个字符串放到pstr指针里了吗

#include<stdio.h>
int main()
{
	const char* pstr = "hello xst";
	printf("%s\n", pstr);
	return 0;
}

答案:本质是把字符串 hello xst ⾸字符的地址放到了pstr中

上⾯代码的意思是把⼀个常量字符串的⾸字符 h的地址存放到指针变量 pstr 中

(首地址,首地址,首地址)

1.1学习《剑指offer》中相关笔试题

#include <stdio.h>

int main()
{
 char str1[] = "hello bit.";
 char str2[] = "hello bit.";
 const char *str3 = "hello bit.";
 const char *str4 = "hello bit.";
 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;
}

//会打印什么??

这⾥str3和str4指向的是⼀个同⼀个常量字符串。C/C++会把常量字符串存储到单独的⼀个内存区域, 当⼏个指针指向同⼀个字符串的时候,他们实际会指向同⼀块内存。

但是⽤相同的常量字符串去初始 化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4相同

2.指针数组&数组指针变量(通过类比通俗易懂一次掌握)

2.1指针数组(指针基础知识点合集2已经讲解)

整型数组:存放整形

字符数组:存放字符

指针数组:存放指针(数组中的每个元素都是用来存放地址(指针)的

2.2数组指针变量(依然需要类比)

整形指针变量:指向整形数据的指针,即存放的是整形变量的地址

字符指针变量:指向字符数据的指针,即存放的是字符变量的地址

数组指针变量:指向数组数据的指针,即存放的是数组数据的地址

2.3两者代码比较

分析两段代码各代表什么意思

1.int *p1[10];

2.int (*p2)[10];

1.首先int和*会先结合,(学会分段:切开一部分一部分看)

int*   p1[10]

划分开再看:p1[10]就是我们最开始学的数组,那int*就是这个数组中元素的类型,也就是每个元素都是整形指针,即这是一个存放整指针的数组,是整形指针数组

2.(*p2)+括号了,因此说明p是一个指针变量,然后指着指向的是⼀个⼤⼩为10个整型的数组,

因此这是一个数组指针变量

3.数组指针变量怎么初始化

数组指针变量是⽤来存放数组地址的,如果要存放个数组的地址,就得存放在数组指针变量中,如下:
 

int(*p)[10] = &arr;

4.⼆维数组传参的本质

⼆维数组传参本质上也是传递了地址,传递的是第⼀ ⾏这个⼀维数组的地址,那么形参也是可以写成指针形式的。如下:

#include <stdio.h>

void test(int (*p)[5], int r, int c)
{
 int i = 0;
 int j = 0;
 for(i=0; i<r; i++)
 {
 for(j=0; j<c; j++)
 {
 printf("%d ", *(*(p+i)+j));
 }
 printf("\n");
 }
}

int main()
{
 int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7}};
 test(arr, 3, 5);
 return 0;
}

5.函数指针变量

函数指针变量是⽤来存放函数地址的,未来通过地址能够调⽤函数的。(依然类比)

例如:

#include <stdio.h>

int Add(int x, int y)
{
 return x+y;
}

int main()
{
 int(*pf3)(int, int) = Add;
 
 printf("%d\n", (*pf3)(2, 3));
 printf("%d\n", pf3(3, 5));
 return 0;
}

6.typedef关键字

重命名(昨天晚上发的顺序表就用了),可以将复杂的类型,简单化。

例如:

typedef unsigned int uint;

//将unsigned int 重命名为uint

7.函数指针数组

那要把函数的地址存到⼀个数组中,那这个数组就叫函数指针数组

int (*parr1[3])();

8.转移表(函数指针数组的⽤途)

举例:计算器的⼀般实现:

#include <stdio.h>

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, y;
 int input = 1;
 int ret = 0;
 do

 {
 printf("*************************\n");
 printf(" 1:add 2:sub \n");
printf(" 3:mul 4:div \n");
 printf(" 0:exit \n");
 printf("*************************\n");
 printf("请选择:");
 scanf("%d", &input);
 switch (input)
 {
 case 1:
 printf("输⼊操作数:");
 scanf("%d %d", &x, &y);
 ret = add(x, y);
 printf("ret = %d\n", ret);
 break;
 case 2:
 printf("输⼊操作数:");
 scanf("%d %d", &x, &y);
 ret = sub(x, y);
 printf("ret = %d\n", ret);
 break;
 case 3:
 printf("输⼊操作数:");
 scanf("%d %d", &x, &y);
 ret = mul(x, y);
 printf("ret = %d\n", ret);
 break;
 case 4:
 printf("输⼊操作数:");
 scanf("%d %d", &x, &y);
 ret = div(x, y);
 printf("ret = %d\n", ret);
 break;
 case 0:
 printf("退出程序\n");
 break;
 default:
 printf("选择错误\n");
 break;
 }
 } while (input);
 return 0;
}

使⽤函数指针数组的实现:

#include <stdio.h>

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, y;
 int input = 1;
 int ret = 0;
 int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表 
 do

 {
 printf("*************************\n");
 printf(" 1:add 2:sub \n");
 printf(" 3:mul 4:div \n");
 printf(" 0:exit \n");
 printf("*************************\n");
 printf( "请选择:" );
 scanf("%d", &input);
 if ((input <= 4 && input >= 1))
 {
 printf( "输⼊操作数:" );
 scanf( "%d %d", &x, &y);
 ret = (*p[input])(x, y);
 printf( "ret = %d\n", ret);
 }
 else if(input == 0)
 {
 printf("退出计算器\n");
 }
 else
 {
 printf( "输⼊有误\n" ); 
 }
}while (input);
 return 0;
}

9.assert断言

assert.h 头⽂件定义了宏 assert() ,在运⾏时确保程序符合指定条件,如果不符合,就报 错终⽌运⾏。这个宏被称为“断⾔”

assert(p != NULL);

assert() 宏接受⼀个表达式作为参数。如果该表达式为真(返回值⾮零), assert() 不会产⽣ 任何作⽤,程序继续运⾏。如果该表达式为假(返回值为零), assert() 就会报错,在标准错误 流 stderr 中写⼊⼀条错误信息,显⽰没有通过的表达式,以及包含这个表达式的⽂件名和⾏号

使⽤ assert() 有⼏个好处:它不仅能⾃动标识⽂件和 出问题的⾏号,还有⼀种⽆需更改代码就能开启或关闭 assert() 的机制。如果已经确认程序没有问 题,不需要再做断⾔,就在 #include 语句的前⾯,定义⼀个宏 NDEBUG

#define NDEBUG
#include <assert.h>

重新编译程序,编译器就会禁⽤⽂件中所有的 assert() 语句。如果程序⼜出现问题,可以移 除这条 #define NDEBUG 指令(或者把它注释掉),再次编译,这样就重新启⽤了 assert() 语 句。

assert() 的缺点是,因为引⼊了额外的检查,增加了程序的运⾏时间。 ⼀般我们可以在 Debug 中使⽤,在 Release 版本中选择禁⽤ assert 就⾏,在 VS 这样的集成开 发环境中,在 Release 版本中,直接就是优化掉了。这样在debug版本写有利于程序员排查问题, 在 Release 版本不影响⽤⼾使⽤时程序的效率

完—

今天的分享就先到这里,每篇涉及的知识点不是很多但都十分相信,希望对大家有所帮助,有什么问题或者指教都可以提出来哈,记得点赞关注哦!

小预告(明日老时间分享):

1.回调函数是什么?

2. qsort使⽤举例

3. qsort函数的模拟实现

等内容

祝大家工作顺利,学业有成!!!

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值