C语言指针面试常考,易混淆

指针

指针概念

变量的地址

1.内存十一字节为单位进行编制的,内存中的每一个字节都对应一个地址,通过地址才能找到每个字节

2.变量对应的内存的的一个单元,这一个单元占据一定的字节数,这个就是变量的地址

32位系统中

任何类型的指针(int * ,char *, float *)占据4个byte int占据4字节 char占据1字节 signed char和unsigned char都是1个字节

short占据2个字节 long占据4个字节 long long 占据8个字节 float占据4字节 double占据8字节

64位系统

除了指针8个字节和long占用8个字节,剩下的都和32位系统一样

其他注意事项 bool类型的大小取决于编译器实现,但通常是1字节. 结构体(struct)和联合体(union)的大小取决于其成员的大小和内存对齐规则。 数组的大小是其元素大小与元素数量的乘积。 void *(通用指针)的大小与系统的指针大小相同,在32位系统上通常是4字节,在64位系统上通常是8字节。 size_t和ptrdiff_t等类型的大小取决于系统和编译器,用于表示对象的大小和指针差异。

指针

指针就是一个地址,变量的地址称为指针

指针变量

用于存储指针的变量称为指针变量,指针变量的值就是变量的地址

指针的定义:类型说明符 *指针变量名

int *p1; float *p1; char *p1;

指针定义的初始化

初始化为空指针:指针变量 = NULL;不指向任何变量 指针定义后不初始化会产生野指针

初始化为变量的地址: 指针变量=&变量 &为取地址运算符,用于获取变量的地址

定义的同时初始化: 类型说明符 *指针变量=NULL; 或者直接=&变量;

指针变量是用来专门存放地址的,不能将任何非地址类型的数据赋给指针变量。一个指针只能指向用一种数据类型的变量

%p输出指针,强制类型转换用int *或者char * float*

段错误

段错误:在编译完成执行程序的时候,出现的模型奇妙的“Segment fault”错误类型

段错误通常是因为访问的内存超出了系统所给的这个程序的内存空间

段错误的成因

操作空指针

操作地址不存在的内存

操作受系统保护的内存

修改常量区的内容

段错误的避免

变量数组指针都要做初始化

数组不要越界操作

通过指针不要访问不存在的内存或者受系统保护的内存

段错误的常见解决方式

分段注释缩小段错误的出现范围

利用GDB调试

指针运算

取地址运算符& 指针运算符* 关系:互为反运算符

指针幅值的形式

将指针变量2中存放的地址直接赋值给指针变量1

左值和右值

左值是变量,在等好左边代表一个存储单元 右值是函数或者表达式,代表存贮单元的值

数组名

数组存储在连续的地址中,数组名就是这块连续内存的首地址,

数组名是一个常量不允许重新赋值

对与指针。P++是针对的内存单元,不是字节,int型一个内存单元是4个字节

常考

前加还是后加

i=P++;和i=++P;

i=P++:后加,后加是先赋值,i=p,然后再执行p++

i=++P;前加,先执行++P,再进行赋值,i=p

函数传递的方式

值传递

数据传输是单向的,由实参传递给形参,不能把形参的值反向传递给实参,

在函数调用过程中,形参的变化不会影响实参

地址传递,指针传递

在函数调用过程中,形参指针本身值得变化不会影响实参指针本身值得变化

但是通过形参指针可以修改实参指针指向存储单元的值

指针数组和数组指针

数组的指针:是一个指针,什么样的指针呢?指向数组的指针。

指针的数组:是一个数组,什么样的数组呢?装着指针的数组。

然后,需要明确一个优先级顺序:()>[]>*,所以:

(*p)[n]:根据优先级,先看括号内,则p是一个指针,这个指针指向一个一维数组,数组长度为n,这是“数组的指针”,即数组指针;

p[n]:根据优先级,先看[],则p是一个数组,再结合,这个数组的元素是指针类型,共n个元素,这是“指针的数组”,即指针数组。

由此可见,对指针数组来说,首先它是一个数组,数组的元素都是指针,也就是说该数组存储的是指针,数组占多少个字节由数组本身决定;而对数组指针来说,首先它是一个指针,它指向一个数组,也就是说它是指向数组的指针,在 32 位系统下永远占 4 字节,至于它指向的数组占多少字节,这个不能够确定,要看具体情况。

指针常量和常量指针

(此二者都是指针类型)

常量指针:通过该指针不可以修改它所指向的内存单元中的值,指针本身的地址可以修改 可以理解为常量的指针,指向常量的指针

定义: 类型说明符 const *指针变量; const(常量) *(指针)从左往右读

类型说明符师指针所指向的存储单元中值的数据类型

指针运算符(*)在关键字const的后边

使用注意点: 可以通过其他指针修改常量指针指向的存储单元中的值

常量指针通常作为阐述的形参使用,目的是在参数中不允许通过该常量指针修改她所知想的存储单元的值

指针常量:指针本身的地址不可以被修改,但可以修改它所指向内存单元的值 可以理解为指针的常量,指针的地址是常量

定义: 类型说明符 * const 指针变量; *(指针) const(常量)从左往右读

使用注意点:

通过指向指针常量的二级指针可以修改他的值,但是在编译时会出现警告

注意二者都可以通过二级指针修改它的值

指向常量的指针常量

指针本身的地址不可以被修改 简而言之,指针和其指向的值都不可以修改

通过该指针不可以修改塔索指向的存储单元中的值 注意不可以通过该指针变量修改,但是可以通过变得指针修改

定义: 类型说明符 const * const 指针变量; int const * const ptr;

上述都是对指针的定义,不是对那个变量的定义

 \#include <stdio.h>
 ​
 int main() {
 ​
   int a=1,b=2;
 ​
   int* const num1=&a;
 ​
   const int* num2=&b;
 ​
   // int **p=&num1;//通过二级指针变化
 ​
   // **p=5;
 ​
   // int *a2=&a;//通过别的指针
 ​
   // *a2=10;
 ​
   // *num1=20;//可以通过指针本身修改常量的值
 ​
   // num1=num2;//指针常量本身的值不能被修改
 ​
 ​
   // int **p=&num2;//通过二级指针变化
 ​
   // **p=5;
 ​
   // *num2=20;//常量指针的值,不可以通过该指针修改常量的值
 ​
   // int *a2=&b;//通过别的指针,可以修改常量指针指向的地址的值
 ​
   // *a2=10;
 ​
   num2=num1;//指针常量本身的值不能被修改,地址可以修改
 ​
   printf("%d,num1:%x\n",a,num1);
 ​
   printf("%d,num2:%x\n",b,num2);
 ​
   printf("%d,num2:%x\n",*num2,num2);
 ​
   return 0;
 ​
 }

变量的存储类型

auto                 自动变量                          局部变量在缺省存储类型的情况下归为自动变量,默认不会初始化,会产生随机值

static                 静态变量                         在程序执行时存在,并且只要整个程序在运行,就可以继续访问该变量。默认会初始化禁进初始化一次

extern         外部变量 (全局变量)        作用域是整个程序,包含该程序的各个文件,生命周期非常长,在程序运行结束后才会释放内存,默认初始化,并只初始化一次

register                 寄存器变量                  存放在CPU寄存器中,对于循环次数较多的循环控制变量以及循环体内部反复使用的变量均可初始化寄存器变量

只能是局部变量,不能是全局变量,不能加static修饰,默认不会初始化。注意在新版c里面很少使用

局部变量存储在栈区

全局变量,静态变量存储在数据段的静态存储区,已经初始化的在初始化区,未初始化的在未初始化区,只初始化一次

变量的内存分配方式

静态存储区上分配

针对全局变量和static变量,程序在编译时编译器就自动对其分配好了内存地址,这块内存在程序的整个运行周期内都存在,这些变量的值在程序运行期间一直存在,知道程序运行结束才会被释放

栈上分配

针对局部变量(包括参数),在每次调用函数时,系统会动态为局部变量在栈中分配内存空间,在函数调用后这些局部变量占有的内存空间会被自动释放

堆上分配

动态内存分配,由程序员调用malloc等函数可以向系统申请任意指定大小的内存,并由程序员自己调用free等函数来释放内存,动态分配内存的生命周期由程序员决定,使用灵活,但是如果忘记释放容易超内存。

变量存储方式

静态存储方式

程序在编译时分配的固定存储空间(静态存储区)的方式,程序执行完毕就释放。全局变量和静态变量属于静态存储方式,存放在静态存储区中

动态存储方式

程序执行期间根据需要进行动态的分配的存储空间(动态存储区),例如,函数的形参,自动变量,局部变量,函数调用时的现场保护和返回地址,函数调用开始时分配动态存储空间,函数调用结束时释放空间

变量和函数:存储类型,链接属性,作用域和生命周期

函数指针和指针函数

指针函数:本质是一个函数,此函数返回某一类型的指针。

函数指针:本质是一个指针,指向函数的指针变量,其包含了函数的地址,通过它来调用函数。

函数指针数组

数组元素师函数指针的数组称之为函数指针数组,也称为转移表

定义: 返回类型说明符 (*函数指针数组名[])(参数列表)={函数指针/函数名1,............,函数指针/函数名n};

int (*str[])(int,int)={add,sub,mul,div}; 使用函数指针数组名[下标](实参列表)

应用场合:

通过使用switch语句可以获得类似的效果,但是使用函数指针数组可以具有更大的灵活性,因为数组元素可以再程序运行时发生变化

可以应用在命令菜单的选择处理上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值