C语言指针
2016-07-17 22:20
162 查看
1.指针的一些基本理解
(1)指针使用三部曲:
①定义指针变量:int *p定义一个指针变量p
②关联指针变量:就是指针的绑定,其意义是让指针指向一个可以访问、应该访问的地方
③解引用:为了间接访问目标变量
(2)指针使用时:
①星号:星号在用于指针相关功能的时候有2种用法:第一种是指针定义时,结合前面的类型用于表明要定义的指针的类型;第二种功能是指针解引用,解引用时*p表示p指向的变量本身
②取地址符&:取地址符使用时直接加在一个变量的前面,然后取地址符和变量加起来构成一个新的符号,这个符号表示这个变量的地址。
③指针定义并初始化、与指针定义然后赋值的区别:
指针定义并初始化:int *p = &a;
指针定义然后赋值:int *p; p = &a;
④左值与右值:放在赋值运算符左边的就叫左值,右边的就叫右值。所以赋值操作其实就是:左值 = 右值。当一个变量做左值时,编译器认为这个变量符号的真实含义是这个变量所对应的那个内存空间;当一个变量做右值时,编译器认为这个变量符号的真实含义是这个变量的值,也就是这个变量所对应的内存空间中存储的那个数。
(3)指针的野指针的问题:
①什么是野指针:野指针,就是指针指向的位置是不可知的,也就是指针变量在定义时如果未初始化,值也是随机的。
②野指针的危害:野指针很可能触发运行时段错误(Sgmentation fault)。
③怎么避免野指针:在指针的解引用之前,一定确保指针指向一个绝对可用的空间。
常规方法:
第一点:定义指针时,同时初始化为NULL
第二点:在指针解引用之前,先去判断这个指针是不是NULL
第三点:指针使用完之后,将其赋值为NULL
第四点:在指针使用之前,将其赋值绑定给一个可用地址空间
④NULL的问题:
#ifdef _cplusplus // 定义这个符号就表示当前是C++环境
#define NULL 0 // 在C++中NULL就是0
#else
#define NULL (void )0 // 在C中NULL是强制类型转换为void 的0
#endif
NULL的实质其实就是0,然后我们给指针赋初值为NULL,其实就是让指针指向0地址处。为什么指向0地址处?2个原因。第一层原因是0地址处作为一个特殊地址(我们认为指针指向这里就表示指针没有被初始化,就表示是野指针);第二层原因是这个地址0地址在一般的操作系统中都是不可被访问的,如果C语言程序员不按规矩(不检查是否等于NULL就去解引用)写代码直接去解引用就会触发段错误,这种已经是最好的结果了。
(4)onst关键字与指针:
const修饰指针有4种形式,区分清楚这4种即可全部理解const和指针。
第一种:const int *p; //p本身不是cosnt的,而p指向的变量是const的
第二种:int const *p; //p本身不是cosnt的,而p指向的变量是const的
第三种:int * const p; // p本身是cosnt的,p指向的变量不是const的
第四种:const int * const p; //p本身是cosnt的,p指向的变量也是const的
2.进一步的指针运用:
(1)以指针方式来访问数组元素:
数组格式访问数组元素是:数组名[下标]; (注意下标从0开始)
指针格式访问数组元素是:*(指针+偏移量);
数组下标方式和指针方式均可以访问数组元素,两者的实质其实是一样的。在编译器内部都是用指针方式来访问数组元素的,数组下标方式只是编译器提供给编程者一种壳(语法糖)而已。所以用指针方式来访问数组才是本质的做法。
(2)指针参与运算的特点:
指针变量+1,并不是真的加1,而是加1*sizeof(指针类型);如果是int 指针,则+1就实际表示地址+4,如果是char 指针,则+1就表示地址+1;如果是double *指针,则+1就表示地址+8.
(3)指针类型和强制装换:
一个指针涉及2个变量:一个是指针变量自己本身,一个是指针变量指向的那个变量。int p;定义指针变量时,p(指针变量本身)是int 类型,*p(指针指向的那个变量)是int类型的。
指针数据类型转换实例分析:int * -> char *:int和char的不同在于char只有1个字节而int有4个字节,所以int的范围比char大。在char所表示的范围之内int和char是可以互转的不会出错;但是超过了char的范围后char转成int不会错,而从int到char转就会出错。
(4)sizeof运算符和strlen函数:
主要是因为在不同平台下各种数据类型所占的内存字节数不尽相同(譬如int在32位系统中为4字节,在16位系统中为2字节···)。所以程序中需要使用sizeof来判断当前变量/数据类型在当前环境下占几个字节。
strlen是一个C库函数,用来返回一个字符串的长度(注意,字符串的长度是不计算字符串末尾的’\0’的)。一定要注意strlen接收的参数必须是一个字符串(字符串的特征是以’\0’结尾)
3.指针与函数之间的关系
(1)指针与函数传参:
①普通变量作为函数形参:函数传参时,普通变量作为参数时,形参和实参名字可以相同也可以不同,实际上都是用实参来替代相对应的形参的。——传值调用
②数组作为函数形参:函数名作为形参传参时,实际传递是不是整个数组,而是数组的首元素的首地址(也就是整个数组的首地址。因为传参时是传值,所以这两个没区别)。所以在子函数内部,传进来的数组名就等于是一个指向数组首元素首地址的指针。所以sizeof得到的是4.—–传址调用
③指针作为函数形参:和数组作为函数形参一样.—–传址调用
④结构体变量作为函数形参:结构体变量作为函数形参的时候,实际上和普通变量(类似于int之类的)传参时表现是一模一样的,只是结构体一般都很大。
(2)输入型参数与输出型参数:
const用来修饰指针做函数传参,作用就在于声明在函数内部不会改变这个指针所指向的内容,所以给该函数传一个不可改变的指针。
如果这个参数是用来做输入的,就叫输入型参数;如果这个参数的目的是用来做输出的,就叫输出型参数。
看到一个函数的原型后,怎么样一眼看出来哪个参数做输入哪个做输出?函数传参如果传的是普通变量(不是指针)那肯定是输入型参数;如果传指针就有2种可能性了,为了区别,经常的做法是:如果这个参数是做输入的(通常做输入的在函数内部只需要读取这个参数而不会需要更改它)就在指针前面加const来修饰;如果函数形参是指针变量并且还没加const,那么就表示这个参数是用来做输出型参数的。
参考:http://www.zhulaoshi.org/
(1)指针使用三部曲:
①定义指针变量:int *p定义一个指针变量p
②关联指针变量:就是指针的绑定,其意义是让指针指向一个可以访问、应该访问的地方
③解引用:为了间接访问目标变量
(2)指针使用时:
①星号:星号在用于指针相关功能的时候有2种用法:第一种是指针定义时,结合前面的类型用于表明要定义的指针的类型;第二种功能是指针解引用,解引用时*p表示p指向的变量本身
②取地址符&:取地址符使用时直接加在一个变量的前面,然后取地址符和变量加起来构成一个新的符号,这个符号表示这个变量的地址。
③指针定义并初始化、与指针定义然后赋值的区别:
指针定义并初始化:int *p = &a;
指针定义然后赋值:int *p; p = &a;
④左值与右值:放在赋值运算符左边的就叫左值,右边的就叫右值。所以赋值操作其实就是:左值 = 右值。当一个变量做左值时,编译器认为这个变量符号的真实含义是这个变量所对应的那个内存空间;当一个变量做右值时,编译器认为这个变量符号的真实含义是这个变量的值,也就是这个变量所对应的内存空间中存储的那个数。
(3)指针的野指针的问题:
①什么是野指针:野指针,就是指针指向的位置是不可知的,也就是指针变量在定义时如果未初始化,值也是随机的。
②野指针的危害:野指针很可能触发运行时段错误(Sgmentation fault)。
③怎么避免野指针:在指针的解引用之前,一定确保指针指向一个绝对可用的空间。
常规方法:
第一点:定义指针时,同时初始化为NULL
第二点:在指针解引用之前,先去判断这个指针是不是NULL
第三点:指针使用完之后,将其赋值为NULL
第四点:在指针使用之前,将其赋值绑定给一个可用地址空间
④NULL的问题:
#ifdef _cplusplus // 定义这个符号就表示当前是C++环境
#define NULL 0 // 在C++中NULL就是0
#else
#define NULL (void )0 // 在C中NULL是强制类型转换为void 的0
#endif
NULL的实质其实就是0,然后我们给指针赋初值为NULL,其实就是让指针指向0地址处。为什么指向0地址处?2个原因。第一层原因是0地址处作为一个特殊地址(我们认为指针指向这里就表示指针没有被初始化,就表示是野指针);第二层原因是这个地址0地址在一般的操作系统中都是不可被访问的,如果C语言程序员不按规矩(不检查是否等于NULL就去解引用)写代码直接去解引用就会触发段错误,这种已经是最好的结果了。
(4)onst关键字与指针:
const修饰指针有4种形式,区分清楚这4种即可全部理解const和指针。
第一种:const int *p; //p本身不是cosnt的,而p指向的变量是const的
第二种:int const *p; //p本身不是cosnt的,而p指向的变量是const的
第三种:int * const p; // p本身是cosnt的,p指向的变量不是const的
第四种:const int * const p; //p本身是cosnt的,p指向的变量也是const的
2.进一步的指针运用:
(1)以指针方式来访问数组元素:
数组格式访问数组元素是:数组名[下标]; (注意下标从0开始)
指针格式访问数组元素是:*(指针+偏移量);
数组下标方式和指针方式均可以访问数组元素,两者的实质其实是一样的。在编译器内部都是用指针方式来访问数组元素的,数组下标方式只是编译器提供给编程者一种壳(语法糖)而已。所以用指针方式来访问数组才是本质的做法。
(2)指针参与运算的特点:
指针变量+1,并不是真的加1,而是加1*sizeof(指针类型);如果是int 指针,则+1就实际表示地址+4,如果是char 指针,则+1就表示地址+1;如果是double *指针,则+1就表示地址+8.
(3)指针类型和强制装换:
一个指针涉及2个变量:一个是指针变量自己本身,一个是指针变量指向的那个变量。int p;定义指针变量时,p(指针变量本身)是int 类型,*p(指针指向的那个变量)是int类型的。
指针数据类型转换实例分析:int * -> char *:int和char的不同在于char只有1个字节而int有4个字节,所以int的范围比char大。在char所表示的范围之内int和char是可以互转的不会出错;但是超过了char的范围后char转成int不会错,而从int到char转就会出错。
(4)sizeof运算符和strlen函数:
主要是因为在不同平台下各种数据类型所占的内存字节数不尽相同(譬如int在32位系统中为4字节,在16位系统中为2字节···)。所以程序中需要使用sizeof来判断当前变量/数据类型在当前环境下占几个字节。
strlen是一个C库函数,用来返回一个字符串的长度(注意,字符串的长度是不计算字符串末尾的’\0’的)。一定要注意strlen接收的参数必须是一个字符串(字符串的特征是以’\0’结尾)
3.指针与函数之间的关系
(1)指针与函数传参:
①普通变量作为函数形参:函数传参时,普通变量作为参数时,形参和实参名字可以相同也可以不同,实际上都是用实参来替代相对应的形参的。——传值调用
②数组作为函数形参:函数名作为形参传参时,实际传递是不是整个数组,而是数组的首元素的首地址(也就是整个数组的首地址。因为传参时是传值,所以这两个没区别)。所以在子函数内部,传进来的数组名就等于是一个指向数组首元素首地址的指针。所以sizeof得到的是4.—–传址调用
③指针作为函数形参:和数组作为函数形参一样.—–传址调用
④结构体变量作为函数形参:结构体变量作为函数形参的时候,实际上和普通变量(类似于int之类的)传参时表现是一模一样的,只是结构体一般都很大。
(2)输入型参数与输出型参数:
const用来修饰指针做函数传参,作用就在于声明在函数内部不会改变这个指针所指向的内容,所以给该函数传一个不可改变的指针。
如果这个参数是用来做输入的,就叫输入型参数;如果这个参数的目的是用来做输出的,就叫输出型参数。
看到一个函数的原型后,怎么样一眼看出来哪个参数做输入哪个做输出?函数传参如果传的是普通变量(不是指针)那肯定是输入型参数;如果传指针就有2种可能性了,为了区别,经常的做法是:如果这个参数是做输入的(通常做输入的在函数内部只需要读取这个参数而不会需要更改它)就在指针前面加const来修饰;如果函数形参是指针变量并且还没加const,那么就表示这个参数是用来做输出型参数的。
参考:http://www.zhulaoshi.org/
相关文章推荐
- C++引用示例&
- C++用mysql自带的头文件连接数据库
- codeforces 527C Glass Carving
- c++11 std::async使用注意
- usaco 2.2.2 subset
- 关于C++ 顶层const和底层const对拷贝操作的影响
- 高级指针
- c++22、string虚假泄露问题,以及简单string类实现
- 必看:学习C语言的思路,让学习不再感到有压力!
- 结构体练习题
- 山东理工OJ 1171 C语言实验——保留整数
- 山东理工OJ 1162 C语言实验——保留字母
- strcat函数用法的一点看法
- C++应用程序性能优化——程序的启动过程
- C语言setpwent()函数:从头读取密码文件中的账号数据
- C语言getpwnam()函数:从密码文件中取得指定账号的数据
- C语言getpwuid()函数:从密码文件中取得指定uid的数据
- C++基础:四大基本函数,构造,析构,拷贝构造,赋值函数
- C++1(Effective C++)
- tmpfile() - C语言库函数