c 函数指针 做参数括号里的参数是两个头指针主调c 函数指针 做参数里就一定要是两个头指针吗

powf 函数说明
功能与pow一致,只是输入与输出皆为浮点数&&因此请参考 pow....-----------------------------------------------原型:extern float pow(float x, float y);&&&&用法:#include &math.h&&&&&功能:计算x的y次幂。&&&&说明:x应大于零,返回幂指数的结果。&&&&举例:&&&&&&// pow.c&&&&&&&&&&&&#include &syslib.h&&&&&&&#include &math.h&&&&&&&main()&&&&&&{&&&&&&&&clrscr();&&&&&&&&// clear screen&&&&&&&&textmode(0x00);&&// 6 lines per LCD screen&&&&&&&&&&&&&&printf("4^5=%f",pow(4.,5.));&&&&&&&&&&&&&&&&getchar();&&&&&&&&return 0;&&&&&&}
C语言标准头
&assert.h& 断言
定义 assert 调试宏。
&ctype.h& 字符类测试
包含有关字符分类及转换的名类信息(如 isalpha和toascii等)
&errno.h& (部分)库函数抛出的错误代码
定义错误代码的助记符。
&float.h& 浮点数运算
包含有关浮点运算的一些参数和函数。
&limits.h& 检测整型数据类型值范围
专门用于检测整型数据数据类型的表达值范围。
&locale.h& 本土化
语言支持本地化设定,如本地格式时间和货币符号.
&math.h& 数学函数
说明数学运算函数,还定了 HUGE VAL 宏, 说明了matherr和matherr子程序用到的特殊结构。
&setjmp.h&
“非局部跳转”
定义longjmp和setjmp函数用到的jmp buf类型, 说明这两个函数。
&signal.h&
定义SIG[ZZ(Z] [ZZ)]IGN和SIG[ZZ(Z] [ZZ)]DFL常量,说明rajse和signal两个函数。
&stdarg.h& 可变参数列表
定义读函数参数表的宏。(如vprintf,vscarf函数)。
&stddef.h& 一些常数,类型和变量
定义一些公共数据类型和宏。
&stdio.h& 输入和输出
定义Kernighan和Ritchie在Unix System V 中定义的标准和扩展的类型和宏。
还定义标准I/O 预定义流:stdin,stdout和stderr,说明 I/O流子程序。
&stdlib.h&
说明一些常用的子程序:转换子程序、搜索/ 排序子程序等。
&string.h&
字符串函数
说明一些串操作和内存操作函数。
&time.h& 时间和日期函数
定义时间转换子程序asctime、localtime和gmtime的结构,ctime、 difftime、 gmtime、 localtime和stime用到的类型,并提供这些函数的原型。
&assert.h& 断言
头文件&assert.h&唯一的目的是提供宏assert的定义。如果断言非真(expression==0),则程序会在标准错误流输出提示信息,并使程序异常中止调用abort() 。定义:void assert (int expression);
//#define NDEBUG
#include &assert.h&
int main(int argc, char* argv[]){
int a = 12;
int b = 24;
assert( a > b );
printf("a is larger than b!");
上面的程序会发现程序中止,printf并未执行,且有这样的输出:
main: Assertion `a > b' failed. 原因就是因为a其实小于b,导致断言失败,assert 输出错误信息,并调用abort()中止了程序执行。
&ctype.h& 字符测试
&ctype.h& 主要提供两类重要的函数:字符测试函数和字符大小转化函数。提供的函数中都以int类型为参数,并返回一个int类型的值。实参类型应该隐式转换或者显示转换为int类型。
判断是否是字母或数字。
判断是否是字母。
判断是否是控制字符。
判断是否是数字。
判断是否是可显示字符。
判断是否是小写字母。
判断是否是大写字母。
判断是否是可显示字符。
判断是否是标点字符。
判断是否是空白字符
判断字符是否为16进制。
转换为小写字母。
转换为大写字母。
&errno.h& 错误代码
error.h 是 C语言 C标准函式库里的头文件,定义了通过错误码来返回错误信息的宏:
errno 宏定义为一个int型态的左值, 包含任何函数使用errno功能所产生的上一个错误码。
一些表示错误码,定义为整数值的宏:
EDOM 源自于函数的参数超出范围,例如 sqrt(-1)
ERANGE 源自于函数的结果超出范围,例如s trtol("0xfffffffff",NULL,0)
EILSEQ 源自于不合法的字符顺序,例如 wcstombs(str, L"\xffff", 2)
&float.h& 浮点数运算
float头文件定义了浮点型数值的最大最小限
浮点型数值以下面的方式定义:符号-value E 指数
符号是正负,value是数字的值
下面的值是用#define定义的,这些值是详细的实现,但是可能没有比这里给出的更详细,
在所有实例里FLT指的是float,DBL是double,LDBL指的是long double
FLT_ROUNDS定义浮点型数值四舍五入的方式,-1是不确定,0是向0,1是向最近,2是向正无穷大,3是负无穷大
FLT_RADIX 2定义指数的基本表示(比如base-2是二进制,base-10是十进制表示法,16是十六进制)
FLT_MANT_DIG,DBL_MANT_DIG,LDBL_MANT_DIG定义数值里数字的个数
FLT_DIG 6,DBL_DIG 10,LDBL_DIG 10在四舍五入之后能不更改表示的最大小数位
FLT_MIN_EXP,DBL_MIN_EXP,LDBL_MIN_EXPFLT_RADIX 的指数的最小负整数值
FLT_MIN_10_EXP -37,DBL_MIN_10_EXP -37,LDBL_MIN_10_EXP -3710进制表示法的的指数的最小负整数值
FLT_MAX_EXP ,DBL_MAX_EXP ,LDBL_MAX_EXPFLT_RADIX 的指数的最大整数值
FLT_MAX_10_EXP +37 ,DBL_MAX_10_EXP ,LDBL_MAX_10_EXP +37 +3710进制表示法的的指数的最大整数值
FLT_MAX 1E+37,DBL_MAX 1E+37,LDBL_MAX 1E+37浮点型的最大限
FLT_EPSILON 1E-5,DBL_EPSILON 1E-9,LDBL_EPSILON 1E-9能表示的最小有符号数
&limits.h& 取值范围
一个ASCII字符长度
字符型最小值
SCHAR_MAX 字符型最大值
无符号字符型最大值
char字符的最大最小值,如果char字符正被表示有符号整数。它们的值就跟有符号整数一样。
否则char字符的最小值就是0,最大值就是无符号char字符的最大值。
MB_LEN_MAX 一个字符所占最大字节数
最小短整型
最大短整形
USHRT_MAX 最大无符号短整型
最大无符号整型
LONG_MIN 最小长整型
LONG_MAX 最大长整型
ULONG_MAX 无符号长整型
&locale.h& 本土化
国家、文化和语言规则集称为区域设置,&locale.h& 头文件中定义了区域设置相关的函数。setlocale函数用于设置或返回当前的区域特性,localeconv用于返回当前区域中的数字和货币信息(保存在struct lconv结构实例中)。setlocale的第一个实参指定要改变的区域行为类别,预定义的setlocale类别有:
LC_ALL 全部本地化信息
LC_COLLATE影响strcoll和strxfrm
LC_CTYPE影响字符处理函数和多行字符处理函数
LC_MONETARY影响localeconv返回的货币格式化信息
LC_NUMERIC影响格式化输入输出字符中的小数点符号
LC_TIME影响strftime函数
&locale.h&
头文件中提供了2个函数
setlocale()
设置或恢复本地化信息
localeconv() 返回当前地域设置的信息
setlocale(constant,location) 用法 如果这个函数成功执行,将返回当前的场景属性;如果执行失败,将返回False。
constant 参数 (必要参数。指定设置的场景信息)
LC_ALL – 所有下属的常量
LC_COLLATE – 排列顺序
LC_CTYPE – 字符分类和转换(例如:将所有的字符转换成小写或大写形式)
LC_MESSAGES – 系统信息格式
LC_MONETARY – 货币 / 通货格式
LC_NUMERIC – 数值格式
LC_TIME – 日期和时间格式
(必要参数)
必要参数。指定需要进行场景信息设置的国家或区域。它可以由一个字符串或一个数组组成。如果本地区域是一个数组,那么setlocale()函数将尝试每 个数组元素直到它从中获取有效的语言和区域代码信息为止。如果一个区域处于不同操作系统中的不同名称下,那么这个参数将非常有用。
struct lconv *localeconv(void); 用法
localeconv 返回lconv结构指针
lconv结构介绍: 保存格式化的数值信息,保存数值包括货币和非货币的格式化信息,localeconv返回指向该对象的指针,以下为结构中的成员及信息:
char *decimal_
数字的小数点号
char *thousands_
数字的千分组分隔符
每个元素为相应组中的数字位数,索引越高的元素越靠左边。一个值为CHAR_MAX的元素表示没有更多的分组了。一个值为0的元素表示前面的元素能用在靠左边的所有分组中
数字分组分隔符
char *int_curr_ 前面的三个字符ISO 4217中规定的货币符号,第四个字符是分隔符,第五个字符是'\0' */
char *currency_ 本地货币符号
char *mon_decimal_
货币的小数点号
char *mon_thousands_ 千分组分隔符
char *mon_ 类似于grouping元素
char *positive_ 正币值的符号
char *negative_ 负币值的符号
char int_frac_ 国际币值的小数部分
char frac_ 本地币值的小数部分
char p_cs_ 如果currency_symbol放在正币值之前则为1,否则为0
char p_sep_by_
当且仅当currency_symbol与正币值之间用空格分开时为1
char n_cs_
char n_sep_by_
当且仅当currency_symbol与负币值之间用空格分开时为1
char p_sign_ 格式化选项
0 - 在数量和货币符号周围的圆括号
1 - 数量和货币符号之前的 + 号
2 - 数量和货币符号之后的 + 号
3 - 货币符号之前的 + 号
4 - 货币符号之后的 + 号
char n_sign_posn 格式化选项
0 - 在数量和货币符号周围的圆括号
1 - 数量和货币符号之前的 - 号
2 - 数量和货币符号之后的 - 号
3 - 货币符号之前的 - 号
4 - 货币符号之后的 - 号
最后提示:可以使用setlocale(LC_ALL,NULL)函数将场景信息设置为系统默认值。
&math.h& 数学函数
是C语言中的数学函数库
*cot三角函数,可以使用tan(PI/2-x)来实现。
反三角函数
结果介于[-PI/2, PI/2]
结果介于[0, PI]
反正切(主值), 结果介于[-PI/2, PI/2]
反正切(整圆值), 结果介于[-PI, PI]
双曲三角函数
计算双曲正弦
计算双曲余弦
计算双曲正切
指数与对数
求取自然数e的幂
以e为底的对数
以10为底的对数
计算以x为底数的y次幂
与pow一致,输入与输出皆为浮点数
标准化浮点数
标准化浮点数, f = x * 2^p, 已知f求x, p ( x介于[0.5, 1] )
与frexp相反, 已知x, p求f
取整与取余
将参数的整数部分通过指针回传, 返回小数部分
返回两参数相除的余数
&setjmp.h&
“非局部跳转”
在该头文件中定义了一种特别的函数调用和函数返回顺序的方式。这种方式不同于以往的函数调用和返回顺序,
它允许程序流程立即从一个深层嵌套的函数中返回。
&setjmp.h& 中定义了两个宏:
int setjmp(jmp_buf env);
/*设置调转点*/
longjmp(jmp_buf jmpb, int retval);
宏setjmp的功能是将当前程序的状态保存在结构env ,为调用宏longjmp设置一个跳转点。setjmp将当前信息保存在env中供longjmp使用。其中env是jmp_buf结构类型的。
&setjmp.h&
static jmp_
void second(void) {
printf("second\n");
longjmp(buf,1);
// 跳回setjmp的调用处
- 使得setjmp返回值为1
void first(void) {
printf("first\n");
// 不可能执行到此行
int main() {
if ( ! setjmp(buf) ) {
// 进入此行前,setjmp返回0
// 当longjmp跳转回,
setjmp返回1,因此进入此行
printf("main\n");
直接调用setjmp时,返回值为0,这一般用于初始化(设置跳转点时)。以后再调用longjmp宏时用env变量进行跳转。程序会自动跳转到setjmp宏的返回语句处,此时setjmp的返回值为非0,由longjmp的第二个参数指定。
一般地,宏setjmp和longjmp是成对使用的,这样程序流程可以从一个深层嵌套的函数中返回。
&signal.h&
在signal.h头文件中,提供了一些函数用以处理执行过程中所产生的信号。
typedef sig_atomic_t
sig_atomic_t
类型是int类型,用于接收signal函数的返回值。
以SIG_开头的宏用于定义信号处理函数
默认信号处理函数。
SIG_ERR 表示一个错误信号,当signal函数调用失败时的返回值。
SIG_IGN 信号处理函数,表示忽略该信号。
SIG开头的宏是用来在下列情况下,用来表示一个信号代码:
SIGABRT 异常终止(abort函数产生)。
SIGFPE 浮点错误(0作为除数产生的错误,非法的操作)。
SIGILL 非法操作(指令)。
SIGINT 交互式操作产生的信号(如CTRL - C)。
SIGSEGV 无效访问存储(片段的非法访问,内存非法访问)。
SIGTERM 终止请求。
void(*signal(int sig,void (*func)(int)))(int);
上面的函数定义中,sig 表示一个信号代码(相当于暗号类别),即是上面所定义的SIG开头的宏。当有信号出现(即当收到暗号)的时候,参数func所定义的函数就会被调用。如果func等于SIG_DFL,则表示调用默认的处理函数。如果等于SIG_IGN,则表示这个信号被忽略(不做处理)。如果func是用户自定义的函数,则会先调用默认的处理函数,再调用用户自己定义的函数。 自定义函数,有一个参数,参数类型为int,用来表示信号代码(暗号类别)。同时,函数必须以return、abort、exit 或 longjump等语句结束。当自定义函数运行结束,程序会继续从被终止的地方继续运行。(除非信号是SIGFPE导致结果未定义,则可能无法继续运行)
如果调用signal函数成功,则会返回一个指针,该指针指向为所指定的信号类别的所预先定义的信号处理器。
如果调用失败,则会返回一个SIG_ERR,同时errno的值也会被相应的改变。
raise 函数
int raise(int sig);
发出一个信号sig。信号参数为SIG开头的宏。
如果调用成功,返回0。否则返回一个非零值。
&stdarg.h&
&stdarg.h& 头文件定义了一些宏,当函数参数未知时去获取函数的参数
变量:typedef va_list
va_start()
变量和定义
va_list类型通过stdarg宏定义来访问一个函数的参数表,参数列表的末尾会用省略号省略
声明:void va_start(va_list ap, last_arg);
用va_arg和va_end宏初始化参数ap,last_arg是传给函数的固定参数的最后一个,省略号之前的那个参数
注意va_start必须在使用va_arg和va_end之前调用
声明:type va_arg(va_list ap, type);
用type类型扩展到参数表的下个参数
注意ap必须用va_start初始化,如果没有下一个参数,结果会是undefined
声明:void va_end(va_list ap);
允许一个有参数表(使用va_start宏)的函数返回,如果返回之前没有调用va_end,结果会是undefined。参数变量列表可能不再使用(在没调用va_start的情况下调用va_end)
&stddef.h& 一些常数,类型和变量
&stddef.h& 头文件定义了一些标准定义,许多定义也会出现在其他的头文件里
宏命令:NULL 和 offsetof()
typedef ptrdiff_t
typedef size_t
typedef wchar_t
变量和定义:
ptrdiff_t是两个指针相减的结果
size_t是sizeof一个关键词得到的无符号整数值
wchar_t是一个宽字符常量的大小,是整数类型
NULL是空指针的常量值
offsetof(type, member-designator);这个宏返回一个结构体成员相对于结构体起始地址的偏移量(字节为单位),type是结构体的名字,member-designator是结构体成员的名字。
&stdio.h& 输入和输出
&stdio.h&头文件定义了用于输入和输出的函数、类型和宏。最重要的类型是用于声明文件指针的FILE。另外两个常用的类型是 size_t和fpos_t,size_t是由运算符sizeof产生的无符号整类型;fpos_t类型定义能够唯一说明文件中的每个位置的对象。由头部 定义的最有用的宏是EOF,其值代表文件的结尾。
typedef size_t
typedef FILE
typedef fpos_t
_IOFBF 表示完全缓冲
_IOLBF 表示线缓冲
_IONBF 表示无缓存
BUFSIZ setbuf函数所使用的缓冲区的大小
EOF EOF是负整数表示END OF FILE
FOPEN_MAX (20)同时打开的文件的最大数量
FILENAME_MAX 文件名的最大长度
L_tmpnam整数,最大长度的临时文件名
SEEK_CUR取得目前文件位置
SEEK_END将读写位置移到文件尾时
SEEK_SET将读写位置移到文件开头
TMP_MAXtmpnam最多次数
stderr标准错误流,默认为屏幕,
可输出到文件。
stdin标准输入流,默认为键盘
stdout标准输出流,默认为屏幕
所有函数(点击可查看介绍和DEMO) :
复位错误标志
关闭一个流。
检测文件结束符
检查流是否有错误
更新缓冲区
移动文件流的读写位置
从文件流读取数据
移动文件流的读写位置
定位流上的文件指针
取得文件流的读取位置
将数据写至文件流
更改文件名称或位置
重设读取目录的位置为开头位置
把缓冲区与流相联
把缓冲区与流相关
以wb+形式创建一个临时二进制文件
 产生一个唯一的文件名
格式化输出数据至文件
格式化字符串输入
格式化输出数据
格式输入函数
格式化字符串复制
格式化字符串输入
格式化输出数据至文件
格式化输出数据
格式化字符串复制
由文件中读取一个字符
文件中读取一字符串
将一指定字符写入文件流中
将一指定的字符串写入文件内
由文件中读取一个字符
由标准输入设备内读进一字符
由标准输入设备内读进一字符串
将一指定字符写入文件中
将指定的字符写到标准输出设备
送一字符串到流stdout中
 将指定字符写回文件流中
打印出错误原因信息字符串
&stdlib.h&
&stdlib.h& 头文件里包含了C语言的中最常用的系统函数
EXIT_FAILURE 失败状态码
EXIT_SUCCESS 成功状态码
RAND_MAX rand的最大返回值
MB_CUR_MAX 多字节字符中的最大字节数
typedef size_t是unsigned integer类型
typedef wchar_t 一个宽字符的大小
struct div_t
是结构体类型 作为div函数的返回类型
struct ldiv_t是结构体类型 作为ldiv函数的返回类型
字符串函数
将字符串转换成浮点型数
将字符串转换成整型数
将字符串转换成长整型数
将字符串转换成浮点数
将字符串转换成长整型数
将字符串转换成无符号长整型数
内存控制函数
配置内存空间
释放原先配置的内存
配置内存空间
重新分配主存
异常终止一个进程
设置程序正常结束前调用的函数
正常结束进程
取得环境变量内容
执行shell 命令
搜索和排序函数
利用快速排序法排列数组
计算整型数的绝对值
将两个整数相除, 返回商和余数
取长整型绝对值
两个长整型数相除, 返回商和余数
随机数发生器
设置随机数种子
多字节函数
根据locale的设置确定字符的字节数
把多字节字符串转换为宽字符串
把多字节字符转换为宽字符
把宽字符串转换为多字节字符串
把宽字符转换为多字节字符
&string.h&
字符串函数
&stdlib.h& 头文件里包含了C语言的最常用的字符串操作函数
typedef size_t
在某一内存范围中查找一特定字符
比较内存内容
拷贝内存内容
拷贝内存内容
将一段内存空间填入某值
连接两字符串
连接两字符串
查找字符串中第一个出现的指定字符
比较字符串
比较2个字符串的前N个字符
采用目前区域的字符排列比较字符串
拷贝字符串
拷贝字符串
返回字符连续不含指定字符的字符数
返回错误原因的描述字符串
计算字符串长度
查找字符串中第一个出现的指定字符
查找字符串中最后出现的指定字符
返回字符串连续不含指定字符的字符数
在一字符串中查找指定的字符串
分割字符串
转换字符串
&time.h& 时间和日期函数
是C标准函数库中获取时间与日期、对时间与日期数据操作及格式化的头文件。
NULL null是一个null指针常量的值
CLOCKS_PER_SEC
每秒的时钟数
typedef size_t 类型定义
typedef clock_t类型定义
struct tm {
/* 秒 – 取值区间为[0,59] */
/* 分 - 取值区间为[0,59] */
/* 时 - 取值区间为[0,23] */
/* 一个月中的日期 - 取值区间为[1,31] */
/* 月份(从一月开始,0代表一月) - 取值区间为[0,11] */
/* 年份,其值等于实际年份减去1900 */
/* 星期 – 取值区间为[0,6],其中0代表星期天,1代表星期一,以此类推 */
/* 从每年的1月1日开始的天数 – 取值区间为[0,365],其中0代表1月1日,1代表1月2日,以此类推 */
/* 夏令时标识符,实行夏令时的时候,tm_isdst为正。不实行夏令时的进候,tm_isdst为0;不了解情况时,tm_isdst()为负。*/
将时间和日期以字符串格式表示
确定处理器时间
把日期和时间转换为字符串
计算两个时刻之间的时间差
把日期和时间转换为(GMT)时间
取得当地目前时间和日期
将时间结构数据转换成经过的秒数
将时间格式化
取得目前的时间扫一扫体验手机阅读
新手,对函数,函数指针,回调函数, 函数指针作为函数的返回值和block的一些见解
<span type="1" blog_id="1615726" userid='
分享到朋友圈
关注作者,不错过每一篇精彩指针_百度百科
清除历史记录关闭
声明:百科词条人人可编辑,词条创建和修改均免费,绝不存在官方及代理商付费代编,请勿上当受骗。
[zhǐ zhēn]
在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的。
在中,指针有效地取代了在低级语言,如与机器码,直接使用通用的地方,但它可能只适用于合法地址之中。指针参考了中某个地址,通过被称为反参考指针的动作,可以取出在那个地址中存储的值。作个比喻,假设将电脑存储器当成一本书,一张内容记录了某个页码加上行号的便利贴,可以被当成是一个指向特定页面的指针;根据便利粘贴面的页码与行号,翻到那个页面,把那个页面的那一行文字读出来,就相当于是对这个指针进行反参考的动作。
在信息工程中指针是一个用来指示一个的计算机语言的变量或(CPU)中(Register)【用来指向该内存地址所对应的变量或数组】。指针一般出现在比较接近的语言,如汇编语言或。的语言如一般避免用指针。指针一般指向一个函数或一个变量。在使用一个指针时,一个程序既可以直接使用这个指针所储存的内存地址,又可以使用这个地址里储存的函数的值。另外,指针也指钟表中用来指示对应时间的部件。
使用指针来读取数据,在重复性操作的状况下,可以明显改善程序性能,例如在字符串,查取表格,控制表格及树状结构上。对指针进行复制,之后再解引用指针以取出数据,无论在时间或空间上,都比直接复制及访问数据本身来的经济快速。
指针的机制比较简单,其功能可以被集中重新实现成更抽象化的(reference)数据形别。许多编程语言中都支持某种形式的指针,最著名的是,但是有些编程语言对指针的运用采取比较严格的限制,如一般避免用指针,改为使用引用。
有两种含义,一是作为数据类型,二是作为实体。
指针作为实体,是一个用来保存一个内存地址的计算机语言中的变量。指针一般出现在比较底层的程序设计语言中,如C语言。高层的语言如Java一般避免用指针,而是引用。
指针作为数据类型,可以从一个函数类型、一个对象类型或者一个不完备类型中导出。从中导出的数据类型称之为被引用类型(referenced type)。指针类型描述了一种对象,其值为对被引用类型的实体的引用。
标准中规定,“指针”概念不适用于(不包含指向静态成员的指针)。C++标准规定,指针分为两类:
object pointer type:指向void或对象类型,表示对象在内存中的字节地址或空指针。
function pointer type:指代一个函数
指针信息工程
指针与C语言
大家都认为,c语言之所以强大,以及其自由性,很大部分体现在其灵活的指针运用上。因此,说指针是c语言的灵魂,一点都不为过。同时,这种说法也让很多人产生误解,似乎只有C语言的指针才能算指针。不支持指针,在此不论。其实,语言本身也是支持指针的。从最初的pascal发展至今的,可以说在指针运用上,丝毫不会逊色于c语言的指针。
内存分配表
计算机中的内存都是的,就像你家的地址一样。在或者运行的时候,系统(可以不关心具体是什么,可能是,也可能是操作系统)开辟了一张表。每遇到一次声明(包括函数的传入参数的声明)都会开辟一个内存空间,并在表中增加一行纪录。记载着一些对应关系。(如图1所示)
Declaration | ID Name Address Length
int nP; | 1 nP 2000 2B
char myC | 2 myChar 2002 1B
int *myP | 3 myPointer 2003 2B
char *myPointer2; | 4 myPointer2 2005 2B
指针,是一个(unsigned int),它是一个以当前系统寻址范围为取值范围的整数。32位系统下寻址能力()是4G Bytes(0~2^32-1)表示长度为32bits(也就是4Bytes), unsigned int类型也正好如此取值。
例证(一)
例证就是程序1得到的答案和程序2的答案一致。(不同机器可能需要调整一下pT的取值)
#include &stdio.h&
char t=&#39;h&#39;;
putchar(*pT);
#include &stdio.h&
char t=&#39;h&#39;;
pT=(char *)1245048;
putchar(*pT);
加上(char *)是因为毕竟int 和char *不是一回事,需要,否则会有个警告。因为char *声明过的类型,一次访问1个sizeof(char)长度,double *声明过的类型,一次访问1个sizeof(double)长度。
在汇编里int 类型和指针就是一回事了。因为不论是整数还是指针,执行自增的时候,都是其值加一。如果上文声明char *pT;,汇编语言中pT自增之后值为1245049,C语言中pT++之后pT值为1245049。如果32 位系统中,上文声明int *pT;,汇编语言中pT 自增之后值为1245049,可是C 语言中pT++之后pT值为1245052。
为什么DOS下面的Turbo C,和Windows下VC的int类型不一样长。因为DOS是16位的,Windows是32位的,可以预见,在64位Windows 中编译,上文声明int *pT;,pT++之后pT值为1245056。
例证(二)
对于复杂的结构,如C语言的(汇编语言对应为Record类型)按顺序分配空间。(如图2所示)
int a[20];
typedef struct st
在32 位系统下,内存里面做如下分配(单位:H,16 进制);(如图3所示)
这就说明了为什么sizeof(pst)=16而不是8。编译器把结构体的大小规定为结构体成员中大小最大的那个类型的整数倍。
至于pT的存储,可以依例推得。总长为160,此不赘述。
有个问题,如果执行pT++,答案是什么?是自增16,还是160?别忘了,pT 是,不能加减。
所以,我们就可以
typedef struct BinTree
struct BinTree *LeftC
struct BinTree *RightC
用一个整数,代表一棵树的结点。把它赋给某个结点的LeftChild/RightChild 值,就形成了上下级关系。只要无法找到一个路径,使得A-&LC/RC-&LC/RC...-&LC/RC==A,这就构成了一棵。反之就成了图。
指针按值传递
C中是按值传递的,传入参数在子函数中只是一个初值相等的副本,无法对传入参数作任何改动。但实际编程中,经常要改动传入参数的值。这一点我们可以用传入参数的地址而不是原参数本身,当对传入参数(地址)取(*)运算时,就可以直接在内存中修改,从而改动原想作为传入参数的。
编程参数值
#include &stdio.h&
void inc(int *val)
printf(&%d& , a);
在执行inc(&a);时,系统在内存分配表里增加了一行“inc 中的val”,其地址为新地址,值为&a。操作*val,即是在操作a 了。
指针*和&运算
(*p)操作是这样一种运算,返回p 的值作为地址的那个空间的取值。(&p)则是这样一种运算,返回当时声明p 时开辟的地址。显然可以用对内存地址赋值。我们假设有这么两段内存地址空间,他们取值如下:(单位:H,16 进制)(如图4所示)
假设有这么一段代码:(假设开辟空间时p 被分配给了3001H、3002H 两个位置)
**p的值为多少?
**p=*(*(p))=*(*(2003H))=*(3000H)=3000H。
那么&&p、*(&p)和&(*p)又等于多少?
&&p=&(&(p))=&(3001H),此时出错了,3001H 是个常数怎么可能有地址呢?
*&p=*(&(p))=*(3001H)=2003H,也就是*&p=p。
&*p=&(*p)=&(3000H)=2003H,之前有人认为这个是不成立的,实际上&(3000H)是求存储3000H这个变量所在的内存地址,仍然是p的值。下面的代码是个很简单的例子:
#include&iostream&
using&namespace&
//环境vc6.0
int&main()
&&&&int&*a;
&&&&a=(int*)5;
&&&&cout&&(unsigned&int)&*a&&
输出的结果为5
指针另类*和&
两个地方要注意: 在程序声明变量的时候的*,只是表明“它是一个无符号整数,这个整数指向某个,一次访问sizeof(type)长度”。这点不要和(*)操作符混淆;
在C++程序声明变量的时候的&,只是表明“它是一个,这个引用声明时不开辟新空间,它在内存分配表加入新的一行,该行内存地址等于和调用时传入的对应参数内存地址”。
这点不要和(*)声明符,(&)操作符混淆。
指针双级指针
对于一棵树,我们通常用它的根节点地址来表示这棵树。这就是“擒贼先擒王”。找到了树的根,其每个都可以找到。但是有时候我们需要对树进行删除节点,增加节点操作,往往考虑到删除根节点,增加的节点取代原来的根节点作为新根节点的情况。为了修改根节点这个“整数”,我们需要退一步,使用这个“整数”的内存地址,也就是指向这个“整数”的指针。在声明时,我们用2 个*号,声明指向指针的指针。它的意思是“它是一个整数,这个整数指向某个内存地址,一次访问sizeof(int)长度,其值是一个整数,那个整数值指向某个内存地址,一次访问sizeof(BTree)长度。”。详见&数据结构&有关“树”的程序代码。由于存放的的地址,因此是指向指针变量的指针变量,或称二级指针变量。
指针指针的初始化
对指针进行初始化或赋值只能使用以下四种类型的值
1. 0 值常量表达式,例如,在编译时可获得 0 值的整型 const对象或字面值常量 0。
2. 类型匹配的对象的地址。
3. 另一对象末的下一地址。
4. 同类型的另一个有效指针。
把 int 型变量赋给指针是非法的,尽管此 int 型变量的值可能为 0。但允
许把数值 0 或在编译时可获得 0 值的 const 量赋给指针:
int zero = 0;
const int c_ival = 0;
int *pi = // error: pi initialized from int value of ival
pi =// error: pi assigned int value of zero
pi = c_// ok: c_ival is a const with compile-time value of 0
pi = 0;// ok: directly initialize to literal constant 0
除了使用数值 0 或在编译时值为 0 的 const 量外,还可以使用 C++ 语言从 C 语言中继承下来的预处理器变量 NULL,该变量在 cstdlib头文件中定义,其值为 0。如果在代码中使用了这个预处理器变量,则编译时会自动被数值 0 替换。因此,把指针初始化为 NULL 等效于初始化为 0 值
// cstdlib #defines NULL to 0
int *pi = NULL; // ok: equivalent to int *pi = 0;
指针与数组关系
:就是一个由指针组成的数组,那个数组的各个元素都是指针,指向某个内存地址。 char *p[10];//p是一个指针数组
:数组名本身就是一个指针,指向数组的首地址。注意这是一个常数。
char (*p)[10]//p是一个数组指针
:本身是一个指针,指向一个函数入口地址,通过该指针可调用其指向的函数,使用函数指针可实现。
#include &stdio.h&
void inc(int *val)
void (*fun)(int *);
fun=//fun是一个函数指针
(*fun)(&a);
printf(&%d& , a);
:本身是一个函数,其返回值是一个指针。
void * fun(void);// fun是一个指针函数
这个问题大家应该都碰到过,指针数组和数组指针,刚开始看时觉得还是能看懂,但是过些时又搞混了,最后发现还是没有真正理解。
下面就简单说说这两个概念:一:指针数组,顾名思义,就是说的首先是一个数组吧,然后数组的元素是指针而已。说明形式为:type *pointer_array[constant1][constant2]...[constantn]; 例如:int *pai[4]; 由于‘*’是自右向左结合,因此从右向左看,首先看到[4]说明是一个数组,是一个包含4个元素的数组,然后看到‘*’,显然是指针类型,由此可以看出数组中存放的是指针而不是一般的类型。同理,char *pac[2][3]是包含有6个元素,每一个元素都是一个字符型指针。再来说说他们的初始化: int *pai[3];既然是一个包含4个整形指针的数组那么其对应的将是一个二维整形数组,因为一个整形指针对应一个一维整形数组。那我就用一个二维整形数组来初始化它,事实上一般也都是这么做的,这里有一个二维数组,int arr[3][2]={{1,2},{3,4},{5,6}},一个三行两列的整形数组,注意这里的行必须和你的指针数组的维数一致,否则是不允许的,不信你可以试试。这个初始化有很多种选择,以下只列举常见的两种:第一种也是很好理解的: for(int i=0;i&3;i++) pai[i]=arr[i]; 显然arr[i]是每一行的首地址,相当于一个一维数组的数组名,如是把它送给一个整形指针pai[i]是理所当然的了。
第二种方法:在说明数组指针时就初始化:int (*ap)[2]={{1,2},{3,4},{5,6}};
注意:不能将二维数组的数组名赋给指针数组的数组名,pai=arr(错),因为两者的类型不一致,二维数组名的类型是指向int[][]型的指针,而指针数组的的数组名是指向int *[]类型的指针。
在c/c++语言中,指针数组最常用的场合就是说明一个字符串数组。即说明一个数组,它的每个元素都是一个字符串。
二:数组指针:指向一个数组的指针。说明形式为:type (*pointer_array)[constant1][constant2]...[constantn]; 注意这里的圆括号是必须就将这是由于方括号[],较指针说明符“*”的优先级高,若无此圆括号,编译器将把上述说明解释成成了一个数组指针。例如:int (*ap)[2]; 这样就说明了一个指向包含有2个元素的整形数组的数组指针,听起来确实有点别扭。不过仔细分析应该还是能理解的,就是说ap是一个指针,而它指向的对象是一个指针,注意不要将它和一个指向一个整形变量的指针搞混了。同样以一个二维数组来说明其初始化问题, int arr[3][2]={{1,2},{3,4},{5,6}};注意这里的列数必须和数组指针所指的数组的列数相同。第一种方法: ap= 为什么这里能这样将二维数组名送给ap呢,你可以这样理解,二维数组不就可以看成是一维数组的数组吗,而一个数组指针它指向的内容就是一个一维数组,那么你就可以把这个数组指针当做是一个数组名,只不过这个数组里的元素不是像int,char之类型的,而是一个数组,这样你就可以把它和二维数组的数组名联系在一起了。
第二种方法: ap=&arr[0]; 这里arr[0]其实就是一维数组的数组名,将它的地址给ap是很自然的,因为ap本来就是指向一个一维数组的。注意这里不能这样初始化:int (*a)[2]={{1,2},{3,4},{5,6}};大家可以想想为什么。当然他们也可以动态赋值,由于篇幅就不探讨了。
指针与“引用”的区别
C++编程中指针与引用的区别
一、指针和引用的区别
(1)引用总是指向一个对象,没有所谓的 null reference .所有当有可能指向一个对象也有可能不指向对象则必须使用 指针.
由于C++ 要求 reference 总是指向一个对象所以 reference要求有初值.
String & rs = string1;
由于没有所谓的 null reference 所以在使用前不需要进行测试其是否有值,而使用指针则需要测试其的有效性.
(2)指针可以被重新赋值而reference则总是指向最初或地的对象.
(3)必须使用reference的场合. Operator[] 操作符 由于该操作符很特别地必须返回 [能够被当做assignment 赋值对象] 的东西,所以需要给他返回一个 reference.
(4)其实引用在函数的参数中使用很经常.
void Get***(const int& a) //这样使用了引用又可以保证不修改被引用的值
★ 相同点:
1. 都是地址的概念;
指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。
1. 指针是一个实体,而引用仅是个别名;
2. 引用使用时无需(*),指针需要解引用;
3. 引用只能在定义时被初始化一次,之后不可变;指针可变;
引用“从一而终”
4. 引用没有 const,指针有 const,const 的指针不可变;
5. 引用不能为空,指针可以为空;
6. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量或对象的地址)的大小;
typeid(T) == typeid(T&) 恒为真,sizeof(T) == sizeof(T&) 恒为真,
但是当引用作为成员时,其占用空间与指针相同(没找到标准的规定)。
7. 指针和引用的自增(++)运算意义不一样;
二、C++中指针传递与引用传递(进一步整理)
从概念上讲。指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变。
而引用是一个别名,它在逻辑上不是独立的,它的存在具有依附性,所以引用必须在一开始就被初始化,而且其引用的对象在其整个生命周期中是不能被改变的(自始至终只能依附于同一个变量)。
在C++中,指针和引用经常用于函数的参数传递,然而,指针传递参数和引用传递参数是有本质上的不同的:
指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的处理,即在中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。(这里是在说实参指针本身的地址值不会变)
而在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
引用传递和指针传递是不同的,虽然它们都是在被调函数栈空间上的一个局部变量,但是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。而对于指针传递的参数,如果改变被调函数中的指针地址,它将影响不到主调函数的相关变量。如果想通过指针参数传递来改变主调函数中的相关变量,那就得使用指向指针的指针,或者指针引用。
为了进一步加深大家对指针和引用的区别,下面我从编译的角度来阐述它们之间的区别:
程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。
最后,总结一下指针和引用的相同点和不同点:
★相同点:
●都是地址的概念;
指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。
★不同点:
●指针是一个实体,而引用仅是个别名;
●引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;
●引用没有const,指针有const,const的指针不可变;(具体指没有int& const a这种形式,而const int& a是有 的, 前者指引用本身即别名不可以改变,这是当然的,所以不需要这种形式,后者指引用所指的值不可以改变)
●引用不能为空,指针可以为空;
●“sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;
●指针和引用的自增(++)运算意义不一样;
●引用是类型安全的,而指针不是(引用比指针多了类型检查)
指针可以用来有效地表示复杂的数据结构,可以用于函数并达到更加灵活使用函数的目的.使C语言程序的设计具有灵活、实用、高效的特点。
谭浩强.《c程序设计》.清华大学出版社:清华大学出版社,2010.6:220
.维基百科&#91;引用日期&#93;
C++Primer第四版中文版
.CSDN 程序员网.&#91;引用日期&#93;
.CSND程序员网.&#91;引用日期&#93;
.ITeye 技术网站.&#91;引用日期&#93;
中国电子学会(Chinese Instit...
提供资源类型:内容
清除历史记录关闭

我要回帖

更多关于 指针数组作为函数参数 的文章

 

随机推荐