C语言数组名与指针

本文详细介绍了C语言中的指针概念,包括指针变量的定义、初始化、赋值以及运算,特别是指针变量的算术运算。同时,文章探讨了数组名在C语言中的特性,指出数组名是数组首元素的地址,其类型根据数组类型有所不同,影响了指针的运算和传参方式。
摘要由CSDN通过智能技术生成

关于指针 “ * ”

C语言形象的将 地址 称为 指针,一个对象的地址称为对象的指针。例如:整型变量 i的地址为 0x00400000, 那么0x00400000就是整型变量的指针。
C语言将专门用来存放地址(指针)的变量称为指针变量。
(这里就要明确指针与指针变量的概念关系,我们平时所说的指针,起始指的是指针变量)

程序中按照对象名称存取对象的方式称为对象直接访问;通过对象地址存取对象的方式称为指针间接访问。指针变量提供了指针间接访问的一个方便方法。

定义指针变量的格式:
//   指向类型 * 指针变量名
	int * p;

一个指针变量有两个关键因素 1.指针变量的值 2.指针变量的指向类型
1.指针变量的值就是他所指向的对象的地址
2.指针变量的指向类型指的是他所指向的对象的数据类型,这个类型可以是传统的 int、 float等也可以是用户自己定义的数据类型。
3.通常编译器为指针变量分配四个字节来存放指针变量的值。

如果两个指针变量的值和他们所指向的数据类型都一样,那么这两个指针变量在做指针间接访问的时候结果是一样的。

关于 void* 类型的指针,他可以保存任何类型对象的地址,表明指针变量与地址相关但是不明确强调对象的类型,通常来说 void* 的用途为

  1. 与另一个指针变量进行比较
  2. 向函数传递一个指针或者从函数返回一个指针(不太强调指向对象类型时)
  3. 给另一个void*赋值
关于指针变量的初始化与赋值

我们已经知道一个指针变量包含两个因素了,那么以后指针变量的很多操作都要围绕着这两个因素展开,
1.获取地址,获取某个对象的地址用取地址操作符 &
2.对于一个指针变量来说不管是初始化还是赋值操作,指针变量的指向类型必须与赋值对象的数据类型是一致的才行否则编译错误。(void*,NULL除外)

    int fenmi[10];
    float fenmf = 0;
    int * i = NULL;
    float *f = NULL;
    f = &fenmf;          //正确
    i = fenmi;           //正确
    i = &fenmi;         // 错误     fenmi是一个  float * 类型的指针常量,是指向  **float数据类型** 的指针常量,
                        //所以第二个对了,但是   &fenmi  这个指针(地址)是一个指向 **一维数组类型**  的指针常量,
                        //但是指针变 量 i 的指向类型是 float  所以二对三错
    f = fenmi;		//错误

不管什么类型的指针变量,在定义时必须初始化,有具体指向的可以直接初始化,没有具体指向的要用NULL初始化

关于指针变量的运算
1.指针变量的算术运算

包括加减整数的运算、自增自减运算、以及两个指针的相减运算,运算结束后得到的值的指向类型与原指向类型相同
一个指针变量或者常量 p 与一个整型数常量或者变量 n 进行加减的结果是一个指针,该结果指向原对象 *p 之后或之前的你 n 个对象。这个结果的值是原来指针的值加上或者减去该对象类型的大小乘以个数n.

#include <stdio.h>
int main()
{
   int x, n = 3, *p = &x;
   printf("p = %x, p + 1 = %x, p + n = %x, p - n = %x\n", p, p + 1, p + n, p - n);
   return 0;
}

输出的结果为

p = 12ff7c, p + 1 = 12ff80, p + n = 121ff88, p - n = 12ff70

一般地,如果指针 p 指向对象的类型为 TYPE 那么 p ± n 的值为 : (p的值) ± n * sizeof(TYPE)
//所以说一个指针变量,对他来说最重要的两个因素就是指针变量的值与该指针变量的指向类型,以上就说明了指针的加减整数的运算与指针变量的值的关系

指针变量的自加自减运算可以看作是指针变量加一减一的操作,与指针变量的加减整数的运算一样。

关于指针的相减运算,要求是必须要求两个指针的指向类型必须一样的,设 p1 是一个指向整型变量的指针变量, p2 也是一个指向整型变量的指针变量,那么 n = p1 - p2; 得到的结果 n 就是两个指针变量的值之间所包含的整型变量的个数,如果, p1 的值大于 p2 那么得到的是一个正值,否则为负值。

指针变量的关系运算,前提依然是两个指针变量的指向类型是一样的

p1 > p2;
p2 != p1;
p1 == NULL;

对于式子1,如果 p1 的值大于 p2 的值那么表达式的值为 真,否则为 假‘
对于式子2和3,表示指针变量也可以进行对比,可以和NULL比较判断该指针变量的值是否为 0 值

指针的强制类型转化
设 p 是一个指针(变量或者常量),可以对 p 进行强制类型转换,形式为:

	  ( 转换类型 *)p

转换之后,产生的临时指针对象,其指向类型为 “转换类型”。

void * 类型的指针不参与指针的算术运算。

指针的 const 限定

有两点
1.指向 const 对象的指针

const 指向类型 * 指针变量名   
(const int * p)

一个指向只读变量的指针变量,这里指针变量 p 本身不是 const 类型的所以 p 的值是可以修改的, p 也不需要初始化,当 p 指向一个对象时(这个对象可以是 const 类型的也可以不是 const 类型的),不能通过指针 p 的间接引用来修改这个对象的值

const int a = 10, b = 20;
int c = 30;
const int * p;
p = &a;
p = &b;
*p = 40;
p = &c;
*p = 50;

上面代码中 第六句是错误的,因为 p 指向的变量 b 是一个 整型 const 类型,不能通过指针变量 p 的间接引用来修改 b 的值;第八句也是错的,虽然 c 不是一个 const 类型的变量,但是指针 p 是一个指向 const 类型对象的指针变量,不能通过指针 p 的间接引用修改指针 p 所指向的变量。
2.const 指针
const 指针指的是这个指针变量本身是一个 const 变量,因此在定义 const 指针的时候必须初始化

指向类型 *const 指针变量名
int a = 10, b = 20;
int *const p = &a;
p = &b;
p = p;
p++;
*p = 100;

上面的代码中定义了一个 const 类型的指针变量 p 同时初始化指向 变量 a ,代码中第三四五句都是错误的,const 类型的指针变量是只读的;但是第六句是正确的,表示可以通过对 const 类型的指针变量的间接引用来改变该 const 指针变量所指向对象的值,但是前提是这个指向对象本身不是 const 类型的变量
另外还有指向 const 变量的 const 指针。

关于数组名

以常规数据类型的数组为例
一维数组

int a[100];

上面定义了有个 int 型的一维数组,大小为100。那么这个数组名 a 是这个一维数组的首地址,她是一个 (int *) 类型的指针常量。他可以做指针与整形数的加减运算。

二维数组

int b[100][100];

上面定义了一个 int 型的二维数组,大小为100*100,整个数组名 b是整个二维数组的数组名,也是一个指针常量,只不过他是 (int *)类型的,它也可以做运算。

上面两个数组名有什么不一样呢
1.值不一样,数组a和数组b存放的地方不一样,所以两者的值是不一样的。
2.两者的指向类型不一样。 a指向的类型为 int 型数据, a 本身是 int * 类型的; b 是 int ** 类型的,他指向的是 int * 类型的数据,换句话说 b 指向的是一维数组类型的数据,所以 b[0]、b[1]等都是一维数组的数组名,同时作为变量来说b[0]、b[1]也都是一维数组的首地址,他们是 int * 类型的变量,指向 int型变量。

这种不一样会影响什么呢
地址的值是我们不太关心的,所以,主要是指针的指向类型,指针的指向类型不同会影响指针各个方面,初始化、赋值、运算、传参等等。
对于运算来讲, 上面已经讲过了,所以这里述说结果
假如说 a 的值为100000,那么 a[0]这个整型数的地址就是 100000,(a + 1)的值就是100004,也就是 a[1]的地址;
假如说 b 的值为1000,那么b[0]的值就是1000,那么 (b + 1)就是 1000 + 1004 = 1400,因为b的指向类型为 int * 型,就是一维数组,所以这个b的指向类型的大小为1004,这个就是b[1]的值。b[0]为1000,那么 b【0】【0】的地址为1000,b[0] + 1的值为1004,就是b【0】【1】的地址,因为 b[0] 是int * 类型的所以指向 int 型数据。
上面是运算数据结果的不同,还有传参时候的注意,因为运算结束后得到的值的指向类型与原指向类型相同,所以传参可能有问题,比如说上面的 (b + 1), 这个值算出来是1400,他是b[1]的值(这主要是由于 b 和 b[0]的值是一模一样的引起的),但是因为 b 是 int ** 类型,所以 这个1400的类型是 int ** 类型的,如果是和函数传参,还需要加一个强制类型转换。

b             1000				int **			指向类型的 int * 也就是指向类型为一维数组类型
b[0]          1000				int *		    指向类型的 int  也就是指向类型为int
b[1]		  1400				int *           指向类型的 int  也就是指向类型为int
b[2]          1800				int *			指向类型的 int  也就是指向类型为int
b[0][0]		  1004				int 
b[0][1]		  1008				int 
b[1][0]		  1400				int 
b[1][1]       1404				int 

从上面指向类型以及各个变量的值、类型来说,我们可以看出这与数据在内存中的存储方式是一致的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值