指针基础知识

程序经过编译后将变量名转换成变量的地址,对变量的存取都是通过地址进行的。

 
一.指针与指针变量
指针:一个变量的地址。指针就是地址
指针变量:专门存放变量地址的变量
 
二.指针的初始化
1.可以用任意合法的指针值进行初始化
2.如果定义指针变量时没有初始化,则系统将根据指针变量的类型选择是否自动初始化指针变量:
  • 全局变量和静态变量将被自动初始化为空指针
  • 局部自动变量、寄存器变量将不被自动初始化,因此它们的值是不确定的,要有明确的变量关联后才能被使用。
3.不能用auto变量的地址初始化static指针
    eg:int i; static int *p = &i;
 
三.函数指针
定义: int (*p)(int,int);
赋值:p = max (max是一个函数,形参为(int,int),返回类型为int)
调用:(*p)(x1,x2)
用途:当一个函数在不同情境下调用形参和返回类型都相同的不同函数(max,min等)时可以不用更改函数代码
 
四.数组与指针
1.数组名在 C语言中被处理成一个地址常量,即数组在内存中的起始地址(数组的指针)。在其生存期内不会改变, 因此, 不能给数组名重新赋值。
2.4种表示数组元素的方法(p是指针,s是数组)
    s[i],    *(s+i),    p[i],    *(p+i) 
3.二维数组与指针
二维数组:在内存中按行存储,每一行视为一个整体
 
(1)例如,有如下定义:
int a[3][4]={{10,20,30,40,},{50,60,70,80},{90,91,92,93}};
则数组a有3个元素,分别为a[0]、a[1]、a[2]。而每个元素都是一个一维数组,各包含4个元素,如a[1]的4个元素是a[1][0]、a[1][1]、a[1]2]、a[1][3]。
若有:
int *p=a[0];
则数组a的元素a[1][2]对应的指针为:p+1*4+2
元素a[1][2]也就可以表示为:*( p+1*4+2)
用下标表示法,a[1][2]表示为:p[1*4+2]
特别说明:
    对上述二维数组a,虽然a[0]、a都是数组首地址,但二者指向的对象不同。
    a[0]是一维数组的名字,它指向的是a[0]数组的首元素,对其进行“*”运算,得到的是一个数组元素值,即a[0]数组首元素值,因此,*a[0]与a[0][0]是同一个值;
    而a是一个二维数组的名字,它指向的是它所属元素的首元素,它的每一个元素都是一个行数组,因此,它的指针移动单位是“行”,所以a+i指向的是第i个行数组,即指向a[i]。对a进行“*”运算,得到的是一维数组a[0]的首地址,即*a与a[0]是同一个值。
    当用int *p;定义指针p时,p的指向是一个int型数据,而不是一个地址,因此,用a[0]对p赋值是正确的,而用a对p赋值是错误的。
 
(2)用二维数组名作地址表示数组元素。
另外,由上述说明,我们还可以得到二维数组元素的一种表示方法:
对于二维数组a,其a[0]数组由a指向,a[1]数组则由a+1指向,a[2]数组由a+2指向,以此类推。因此,*a与a[0]等价、*(a+1)与a[1]等价、*(a+2)与a[2]等价,┅,即对于a[i]数组,由*(a+i)指向。由此,对于数组元素a[i][j],用数组名a的表示形式为:
*(*(a+i)+j)
指向该元素的指针为:
*(a+i)+j
数组名虽然是数组的地址,但它和指向数组的指针变量不完全相同。指针变量的值可以改变,即它可以随时指向不同的数组或同类型变量,而数组名自它定义时起就确定下来,不能通过赋值的方式使该数组名指向另外一个数组。
 

(3)行数组指针
在上面的说明中我们已经知道,二维数组名是指向行的,它不能对如下说明的指针变量p直接赋值:
int a[3][4]={{10,11,12,13},{20,21,22,23},{30,31,32,33}},*p;
其原因就是p与a的对象性质不同,或者说二者不是同一级指针。C语言可以通过定义行数组指针的方法,使得一个指针变量与二维数组名具有相同的性质。行数组指针的定义方法如下:
数据类型 (*指针变量名)[二维数组列数];
例如,对上述a数组,行数组指针定义如下:
int (*p)[4];

数据类型 (*指针变量)[];
它表示,数组*p有4个int型元素,分别为(*p)[0]、(*p)[1]、(*p)[2]、(*p)[3] ,亦即p指向的是有4个int型元素的一维数组,即p为行指针

此时,可用如下方式对指针p赋值:
p=a;

(备注:一般的指针,int*p,也可以指向一个数组,元素为p[0],p[1],...但二者的基类型不同,行数组指针的基类型是一个行数组,而一般的指针的基类型是一个int型)
 
五.指针与字符串

1.用字符数组指向字符串和用字符指针指向的字符串的区别

如:char  *str="OK"; 与 char a[]="OK";

  • str 是指针变量,可多次赋值;a 是数组名,表示地址常量,不能赋值,且 a 的大小固定,预先分配存储单元。
  • 类型、大小不同。str 是指针,a 是数组。它们的存储表示如图所示。
           
  • a 的元素可重新赋值,不能通过 str 间接修改字符串常量的值。

例题一

答案:
1.float(**def)[10];
def是一个二级指针,它指向的是一个一维数组的指针
2.double*(*gh)[10]
gh是一个指针,指向一个一维数组,数组元素是double*
3.double*(*f[10])();
f是一个有十个元素的数组,每个元素为函数指针
4.int *((*b)[10])
同2,b是一个指针,指向一个一维数组,数组元素是int*
5.long(*fun)(int)
fun是一个函数指针
6.int(*(*F)(int,int))(int)
F是一个函数指针,指向的函数为有两个int参数并返回函数指针的函数,返回的函数指针指向形参为一个int参数返回值为int的函数
 

 例题二

分析:数组名本身就是指针,再加个&就变成了指针的指针即二维指针,加一,就是数组整体加一行。
答案:1,5
 
例题三
空指针与迷途指针的区别?
答案:当delelte释放一个指针时,实际上是编译器释放内存,但指针本身依然存在,这时它就是迷途指针。当使用赋值语句将0赋给迷途指针时就可以将迷途指针改为空指针。
            如果在一个迷途指针被多次重复删除,程序会变得很不稳定,可能发生任何事情。但是删除空指针是安全的。
            使用迷途指针或空指针是非法的,可能造成程序崩溃。如果是空指针,它所造成的崩溃相比迷途指针是一种可预料的崩溃,更便于调试。
 
例题四
C++中有了malloc/free,为什么还需要new/delete?
答案:malloc/free是C++/C的标准库函数,new/delete是C++的运算符。它们都可用于动态申请内存和释放内存。
         对于非内置数据类型的对象而言,malloc/free无法完成申请动态内存的要求。因为对象在创建的同时要自动执行构造函数,在消亡之前要自动执行析构函数。而malloc/free是库函数不是运算符,不能做到自动执行创建对象的构造函数与析构函数。
        因此C++语言需要一个能自动完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。new/delete 不是库函数,而是运算符。
原文地址:https://www.cnblogs.com/happygirl-zjj/p/4636045.html