C语言指针

指针

一、指针变量

1.概念

存储地址,占4字节的空间

类型:存放的地址指向的数据类型

vs

普通变量根据不同类型占内存空间不同:char(1字节)、short(2字节)、int(4字节)、long(4字节)、long long (8字节)、float(4字节)、double(8字节)

2.初始化和操作

int f = 123;
int *p = &f;
int f2 = 456;
p = &f2;  修改指针指向
*p = 789; 修改指针指向的数据

3.指向常量的指针和常量指针

3.1指向常量的指针

(1)指针可以修改为指向不同的常量

(2) 指针可以修改为指向不同的变量

(3) 可以通过解引用来读取指针指向的数据

(4)不可以通过解引用修改指针指向的数据;

int num = 520;
const int cnum = 880;
const int *pc = &cnum;
*pc = 1024; //error:不可以通过解引用修改指针指向的数据
pc = #  //可以修改指向
3.2指向非常量的常量指针

(1)指针自身不可以被修改:p = &b;(对int *const p = &a;)

(2)指针指向的值可以被修改。

int num = 520;
const int cnum = 880;
int *const p = #
*p = 1024;  ///指针指向的值可以被修改
p = &cnum;  ///指针自身不可以被修改指向
3.3指向常量的常量指针

(1)指针自身不可以被修改。

(2)指针指向的值可以被修改。

int num = 520;
const int cnum = 880;
int *const p = &cnum;
指针指向的数据不能通过对指针解引用来修改,指针自身也不能被修改指向

二、数组指针和指针数组

int *p1[5]; 	//指针数组
int (*p2)[5]; 	//数组指针

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

1.定义

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

数组指针:是指针,指向一个数组。数组在这里并没有名字,是个匿名数组。

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

指针数组:是一个数组,每个数组元素存放一个指针变量。

2.区别

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

3.数组指针(*p)[n]

#include "stdafx.h"
 
 
int main()
{
	//一维数组
	int a[5] = { 1, 2, 3, 4, 5 };
	//步长为5的数组指针,即数组里有5个元素
	int (*p)[5];
	//把数组a的地址赋给p,则p为数组a的地址,则*p表示数组a本身
	p = &a;
 
	//%p输出地址, %d输出十进制
	//\n回车
	//在C中,在几乎所有使用数组的表达式中,数组名的值是个指针常量,也就是数组第一个元素的地址,它的类型取决于数组元素的类型。
	printf("%p\n", a); //输出数组名,一般用数组的首元素地址来标识一个数组,则输出数组首元素地址
	printf("%p\n", p); //根据上面,p为数组a的地址,输出数组a的地址
	printf("%p\n", *p); //*p表示数组a本身,一般用数组的首元素地址来标识一个数组
	printf("%p\n", &a[0]); //a[0]的地址
	printf("%p\n", &a[1]); //a[1]的地址
	printf("%p\n", p[0]); //数组首元素的地址
	printf("%d\n", **p); //*p为数组a本身,即为数组a首元素地址,则*(*p)为值,当*p为数组首元素地址时,**p表示首元素的值1
	printf("%d\n", *p[0]); //根据优先级,p[0] 表示首元素地址,则*p[0]表示首元素本身,即首元素的值1
	printf("%d\n", *p[1]); //为一个绝对值很大的负数,不表示a[1]...表示什么我还不知道
 
	
 
	//将二维数组赋给指针
	int b[3][4];
	int(*pp)[4]; //定义一个数组指针,指向含4个元素的一维数组
	pp = b; //将该二维数组的首地址赋给pp,也就是b[0]或&b[0],二维数组中pp=b和pp=&b[0]是等价的
	pp++; //pp=pp+1,该语句执行过后pp的指向从行b[0][]变为了行b[1][],pp=&b[1]
 
	int k;
	scanf_s("%d", &k);
 
    return 0;
}
 
 
 

4.指针数组*p[n]

#include "stdafx.h"
 
 
int main()
{
	int a = 1;
	int b = 2;
	int *p[2];
	p[0] = &a;
	p[1] = &b;
 
	printf("%p\n", p[0]); //a的地址
	printf("%p\n", &a); //a的地址
	printf("%p\n", p[1]); //b的地址
	printf("%p\n", &b); //b的地址
	printf("%d\n", *p[0]); //p[0]表示a的地址,则*p[0]表示a的值
	printf("%d\n", *p[1]); //p[1]表示b的地址,则*p[1]表示b的值
 
 
	//将二维数组赋给指针数组
	int *pp[3]; //一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2],所以要分别赋值
	int c[3][4];
	for (int i = 0; i<3; i++)
		pp[i] = c[i];
 
	int k;
	scanf_s("%d", &k);
 
    return 0;
}
 

5.初始化

(1)数组指针

数组名的值是个指针变量,也就是数组第一个元素的地址

error//
int (*p2)[5] = {1,2,3,4,5};
/*
p2是一个指针,所以要给它的是一个地址
*/
//==>
int temp[5] = {1,2,3,4,5};
int (*p2)[5] = temp;
/*
指针类型初始化不一致
在 C 语言中,赋值符号“=”号两边的数据类型必须是相同的,如果不同,则需要显示或隐式类型转换。
“=”号两边的数据类型就不一致了(左边的类型是指向整个数组的指针,而右边的数据类型是指向单个字符的指针),因此会提示错误信息。
*/
//==>
/right//
int *p = temp;
/*
此时这个指针(只是一个指向整型变量的指针,而不是指向数组的指针)指向数组的第一个元素,而不是数组。因为数组的所有元素都是一个挨着存放,所以知道第一个元素的地址,就可以遍历后面的所有元素。
*/
int (*p2)[5] = &temp;
/*
把数组temp的地址赋给p2,则p2为数组temp的地址,则*p2表示数组temp本身
*/
//===>真正的数组指针

(2)指针数组

int *p1[5] = {&a,&b,&c,&d,&e};

三、指针和二维数组

对二维数组:int array[4] [5]

array:整个二维数组的首地址。指向包含5个元素的数组的指针(地址)。

*(array+1):相当于array[1],而array[1]相当于array[1] [0]的数组名,即 *(array+1)是指向第二行子数组第一个元素的地址。

((array+1)+3):指向第二行子数组第四个元素的指针,在对进行取值

int (*p)[4];
// *(*(p+i)+j):指向第i+1行子数组第j+1个元素的指针的值
int array[3][4] = {
    {0,1,2,3},
    {4,5,6,7},
    {8,9,10,11}
};
int i, j;
p = array;
for (i = 0;i < 3;i++){
    for (j = 0;j < 4; j++){
        printf("%2d ",*(*(p+i)+j));
    }
    printf("\n");
}
//通过数组指针的方式来访问二维数组

四、void指针

无类型指针,不用来定义一个变量

通用指针,可以指向任何类型的数据

不要对void指针直接进行解引用,因为编译器不知道它指向的什么数据类型,需要强制类型转换:

int num = 1024;
int *pi = &num;
char *ps = "Andyli";
void *pv;

pv = pi;
printf("pi:%p,pv:%p\n",pi,pv);
printf("*pv:%d\n",*pv);				///error
===>
printf("*pv:%p\n",*(int *)pv);		1024

五、NULL指针

#define NULL ((void *)0)

一个良好的编程习惯:当不清楚要将指针初始化为什么地址时,请将它初始化为NULL;在对指针进行解引用时,先检查该指针是否为NULL。这种习惯可以为以后编写大型程序节省大量的调试时间。

六、指针数组和指向指针的指针

char **p[4];	//p定义的是一个数组,里面存放的是指向字符指针的指针变量

//对于一个指针数组p2
char *p2[] = {
    .....
};
/*对&p2[5]得到的是字符串的首地址,即在这里是指向字符指针的指针
	则对 char **p3 可以将&p2[5]赋值给p3
	即 p3 = &p2[5]
*/
// 此时*p3(对p3解引用),得到p2[5]的值
// 使用指向指针的指针来指向数组指针,避免重复分配内存
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

森奈a

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值