(第13章)高级指针话题

2024-06-08 07:08
文章标签 指针 高级 13 话题

本文主要是介绍(第13章)高级指针话题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 1.指向指针的指针
    • 2.高级声明
    • 3.函数指针
      • (1)用途1:回调函数
      • (2)用途2:转移表
    • 4.传递命令行参数
    • 5.字符串常量
    • 6.总结

1.指向指针的指针

  • 看eg:
int i;
int *pi;
int **ppi;ppi=π//把ppi初始化为指向变量pi
*ppi=&i;//把pi(通过ppi的间接访问)初始化为指向变量i,这里的*ppi指针就是pi指针//变量i是一个整数,pi是一个指向整型的指针,ppi是一个指向pi的指针,所以它是一个指向整型的指针的指针。
等价于://按照我下面的写法比较好
pi=&i;
ppi=π
  • 经过上面的两条语句后,变量变成下面的样子:
    在这里插入图片描述
  • 现在,下面的语句的赋值效果是一样的
i='a';
*pi='a';
**ppi='a';

2.高级声明

int f;//一个整型变量
int *f;//一个指向整型的指针,表达式*f声明为一个整数,f是指向整型的指针
int *f();//函数调用的操作符()的优先级高于间接访问的操作符,so,f是一个函数,它的返回值类型是一个指向整型的指针;
int (*f)();//第一个括号迫使间接访问在函数调用之前进行,so,f成为了一个函数指针,它所指向的函数返回一个整数值;
int *(*f)();//f是一个函数指针,函数的返回值是一个指针;int *f[];//下标的优先级高于间接访问的操作符,so,f是一个数组,它的元素类型是指向整型的指针;
int f()[];//非法!f是一个函数,返回值是整型数组,而函数不能返回数组
int f[]();//非法!f似乎是一个数组,它的元素类型是返回值为整型的函数。而数组元素必须有相同的长度,但不同的函数显然
可能具有不同的长度int (*f[])()//f是一个元素为某种类型的指针的数组,函数元素的类型是函数指针,它所指向的函数的返回值是一个整型值;
int *(*f[])()//声明创建了一个指针数组,指针所指向的类型是返回值为整型指针的函数//ANSI C提倡的函数原型的风格如下
int (*f)(int ,foat)//f声明为一个指针,它所指的函数接受两个参数:一个int,一个float,并返回一个intint (*g[])(int, float)//g声明为一个数组,数组的元素类型是一个函数指针,它所指向的函数接受两个参数:一个int
,一个float,并返回一个int型指针

3.函数指针

(1)用途1:回调函数

  • 初始化函数指针
int f(int);//函数f的原型
int (*pf)(int)=&f;//创建函数指针pf,并把它初始化为指向函数f;
//初始化表达式的&操作符是可选的,因为函数名被使用时,总是由编译器把它转化为函数指针
  • 初始化函数指针,如何调用函数?
ans=f(25);//使用名字调用函数f,函数名f首先被转换为一个函数指针,该指针指定函数在内存中的位置,然后,函数调用操
作符来调用该函数,执行开始于这个地址的代码ans=(*pf)(25);//将函数指针转换为一个函数名。其执行效果和上面的语句类似ans=pf(25);//间接访问操作并非必须,因为编译器需要的是一个函数指针。其显示了函数指针通常是如何使用的。
  • 回调函数callback function
    定义:用户把一个函数的指针作为参数传递给其他函数,后者将回调用户的函数。
    *我们无法在上下文环境中为回调函数编写一个准确的原型,所以把其参数类型声明为void ,表示一个指向未知类型的指针

  • eg:

//在一个单链表中查找一个指定值的函数。它的参数是一个指向链表的第一个节点的指针,一个指向我们需要查找的值的指针和一个函数指针,
//他所指向的函数用于比较存储于链表中的类型的值。
#include <stdio.h>
#include "node.h"Node *serach_list(Node *node, void const *value, int (*compare)(void const *, void const *))
{while (node!=NULL){if (compare(&(node->value), value)==0)break;node=node->link;}return node;
}//用于整型链表中查找的比较函数如下,将指向该函数的指针和指向需要查找的值的指针传递给serach_list函数
//比较函数的参数必须声明为void*以匹配serach_list函数的原型,然后它们再强制转换为int*类型,用于比较整型值。
int (*compare)(void const *a, void const *b)
{if (*(int *)a==*(int *)b)return 0;elsereturn 1;
}//使用
desired_node=serach_list(root, &desired_value, compare_ints);

(2)用途2:转移表

  • 下面是实现一个计算器
输入两个数op1和op2和一个操作符oper,来选择调用哪个函数
switch (oper)
{case ADD:result=add(op1,op2);break;case SUB:result=sub(op1,op2);break;case MUL:result=mul(op1,op2);break;case DIV:result=div(op1,op2);break;。。。
}
优点:把具体操作和选择操作的代码分开是一种良好的设计方法。
缺点:若由上百个操作符,switch会很长
  • 转换表:转换表就是一个函数指针数组
创建一个转换表:
(1)声明并初始化一个函数指针数组,要确保这些函数的原型出现再这个数组的声明之前
double add(double, double);
double sub(double, double);
double mul(double, double);
double div(double, double);
...//初始化列表中各个函数名的正确顺序取决于程序中用于表示每个操作符的整型代码。
//假定ADD=0,SUB=1,MUL=2
double (*oper_func[])(double, double)={add,aub,mul,div,。。。}2)用下面的语句替换前面的整条switch语句
result=oper_func[oper](op1,op2);
oper从数组中选择正确的函数指针,而函数调用操作符将执行这个函数

4.传递命令行参数

  • C程序的main函数具有两个参数:第1个参数称之为argc,表示命令行参数的数目,第2个参数称为argv,它指向一组参数值,argv指向这组参数值(本质是一个数组,这些元素的每个都是指向一个参数文本的指针)的第1个元素
int main(int argc, char **argv)//命令行如何传递
cc -c -o main.c insert.c -o testargv是一个指针数组,这个数组的每个元素都是一个字符指针,数组的末尾是一个NULL指针
argv指向数组的第一个元素,所以被声明为指向字符的指针的指针的原因
第一个参数是程序的名称

在这里插入图片描述

  • 打印命令行参数的eg,类似于unix的echo命令
#include <stdio.h>
#include <stdlib.h>int main(int argc, char**argv)
{//打印参数,直到遇到NULL指针,程序名被跳过while (*++argv!=NULL)printf("%s\n", *argv);return EXIT_SUCCESS;
}//上面的代码把每个参数都与表示列表末尾的NULL指针进行比较
//程序名被跳过了。。
//printf的%s格式码要求:参数是一个指向字符的指针,printf假定该字符是一个以NULL字符结尾的字符串的第1个字符。
  • 命令行参数和命令行参数前面的选项参数
命令行参数前面的选项参数:每个选项都以一条横杠开头,后面是一个字母
如果命令行中没有文件名,就对标准输入进行处理
prog -a -b -c name1 name2 name3
  • 如何区分选项参数和文件名参数?
//处理命令行参数
#include <stdio.h>
#define TRUE 1//执行实际任务的函数的原型
void process_standard_input(void);
void process_file(char *file_name);int option_a, option_b;void main(int argc, char **argv)
{//处理选项参数while (*++argv!=NULL && **argv=='-'){/*switch语句和下面的语句时等价的。若字符非NULL,那么就像前面一样使用switch语句来设置合适的变量。while((opt=*++*(argv)!='\0')){switch(opt){case 'a':option_a=TRUE;break;}}*///检查横杠后面的字母switch(*++(*argv))//第一个*访问argv所指的位置,然后进行自增操作,最后一个*操作根据自增后的指针进行访问{case 'a':option_a=TRUE;break;case 'b':option_b=TRUE;break;}//处理文件名参数//当不再存在其他选项时,程序就处理文件名。如果argv指向NULL指针,命令行参数里就没有别的东西了,//程序就处理标准输入。//否则,程序就逐个处理文件名。if (*argv==NULL)process_standard_input();else{do{process_file(*argv);}while(*++argv!=NULL);}}
}
  • 访问参数和访问参数中的下一个字符的图如下,
    在这里插入图片描述
    在这里插入图片描述

5.字符串常量

  • 当一个字符串常量出现于表达式中时,它的值是一个指针常量。编译器把这些指定字符的一份拷贝再内存的某个位置,并存储一个指向第1个字符的指针。
    当数组名用于表达式时,它们的值也是指针常量。我们可以对他们进行下标引用,间接访问,以及指针运算。
"xyz"+1
表示:指针值+1,结果是个指针,指向字符串的第二个字符:y*"xyz"
表示:因为对一个指针执行间接访问操作时,其结果就是指针所指向的内容。字符串常量的类型时”指向字符的指针“,所
以该结果就是:他所指向的字符:x,"xyz"[2]
表示:表达式的值就是字符z*("xyz"+4)
表示:因为偏移量4超出了这个字符串的范围,所以该表达式的结果时一个不可预测的字符
  • 接受一个整型值,把他转换为字符的eg
//接受一个整型值,把他转换为字符,并打印出来,前导零被去除
void binary_to_ascii(unsigend int value)
{unsigend int quotient;quotient=value/10;if (quotient!=0)binary_to_ascii(quotient);//把二进制值转换为字符并把它们都打印出来putchar(value%10+'0');
}代码要求:
以十六进制的形式打印结果值
remainder=value%16的余数可能是0-15的任何值,10-15的值应该以字母A-F来表示
在任何常见的字符集中,字母A-F并不是立即位于数字的后面典型的方法如下:
remainder=value%16;
if (remainder<10)putchar(remainder+'0');
elseputchar(remainder-10+'A');又一种方法如下:
putchar("0123456789ABCDEF"[value%16]);
  • 神秘函数
//参数是一个0-100的值
#include <stdio.h>void mystery(int n)
{n+=5;n/=10;printf("%s\n","*********"+10-n);
}
//若参数为0,就打印0个星号
//若参数为100,就打印10个星号
//位于0-100的参数值就打印出0-10个星号

6.总结

  • 一个指针变量可以指向另一个指针变量,一个指向指针的指针在它使用之前必须进行初始化
  • int *a; *a声明为一个整型,a是一个指向整型的指针
  • 函数指针:函数指针可以实现回调函数,一个指向回调函数的指针作为参数传递给另一个函数,后者使用这个指针调用回调函数;转移表也可以使用函数指针,转移表像switch语句一样执行选择,转移表由一个函数指针数组组成(这些函数必须具有相同的原型),函数通过下标选择某个指针,再通过指针调用对应的函数。
  • 命令行参数:argc和argv。他们传递给main函数,argc是一个整数,用于表示参数的数量,argv是一个指针,它指向一个序列的字符型指针,该序列中的每个指针指向一个命令行参数,该序列以一个NULL指针作为结束标志。
    第一个参数是程序的名字。
  • 字符串常量就是一个常量指针,它指向字符串的第1个字符。和数组名一样,可以用指针表达式,也可以用下标来使用字符串常量。

参考:<C和指针>

这篇关于(第13章)高级指针话题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1041491

相关文章

深入解析Spring TransactionTemplate 高级用法(示例代码)

《深入解析SpringTransactionTemplate高级用法(示例代码)》TransactionTemplate是Spring框架中一个强大的工具,它允许开发者以编程方式控制事务,通过... 目录1. TransactionTemplate 的核心概念2. 核心接口和类3. TransactionT

Python中列表的高级索引技巧分享

《Python中列表的高级索引技巧分享》列表是Python中最常用的数据结构之一,它允许你存储多个元素,并且可以通过索引来访问这些元素,本文将带你深入了解Python列表的高级索引技巧,希望对... 目录1.基本索引2.切片3.负数索引切片4.步长5.多维列表6.列表解析7.切片赋值8.删除元素9.反转列表

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

【C++学习笔记 20】C++中的智能指针

智能指针的功能 在上一篇笔记提到了在栈和堆上创建变量的区别,使用new关键字创建变量时,需要搭配delete关键字销毁变量。而智能指针的作用就是调用new分配内存时,不必自己去调用delete,甚至不用调用new。 智能指针实际上就是对原始指针的包装。 unique_ptr 最简单的智能指针,是一种作用域指针,意思是当指针超出该作用域时,会自动调用delete。它名为unique的原因是这个

C语言指针入门 《C语言非常道》

C语言指针入门 《C语言非常道》 作为一个程序员,我接触 C 语言有十年了。有的朋友让我推荐 C 语言的参考书,我不敢乱推荐,尤其是国内作者写的书,往往七拼八凑,漏洞百出。 但是,李忠老师的《C语言非常道》值得一读。对了,李老师有个官网,网址是: 李忠老师官网 最棒的是,有配套的教学视频,可以试看。 试看点这里 接下来言归正传,讲解指针。以下内容很多都参考了李忠老师的《C语言非

Java基础回顾系列-第七天-高级编程之IO

Java基础回顾系列-第七天-高级编程之IO 文件操作字节流与字符流OutputStream字节输出流FileOutputStream InputStream字节输入流FileInputStream Writer字符输出流FileWriter Reader字符输入流字节流与字符流的区别转换流InputStreamReaderOutputStreamWriter 文件复制 字符编码内存操作流(

Java基础回顾系列-第五天-高级编程之API类库

Java基础回顾系列-第五天-高级编程之API类库 Java基础类库StringBufferStringBuilderStringCharSequence接口AutoCloseable接口RuntimeSystemCleaner对象克隆 数字操作类Math数学计算类Random随机数生成类BigInteger/BigDecimal大数字操作类 日期操作类DateSimpleDateForma

C和指针:字符串

字符串、字符和字节 字符串基础 字符串就是一串零个或多个字符,并且以一个位模式为全0的NUL字节结尾。 字符串长度就是字符串中字符数。 size_t strlen( char const *string ); string为指针常量(const修饰string),指向的string是常量不能修改。size_t是无符号数,定义在stddef.h。 #include <stddef.h>