从零到一看指针(C语言)

马肤
这是懒羊羊

亲爱的友友们,不知你们是否理解c语言的指针呢?

如果并不了解,或是有些许困惑,不妨来看看这篇文章吧,希望你能从中有所启发(手动比心)

目录

1.初识指针

1.1 举例——交换两数值 

1.2 指针的相关符号 —— * ,&

1.3指针+-整数

1.4 const修饰指针变量 

1.5 野指针 

2.数组与指针

 2.1数组名

2.2一维数组传参

 3.二级指针

4.指针数组

5.数组指针 

 6.函数指针

7.函数指针数组


1.初识指针

1.1 举例——交换两数值 

首先让我们来看一个程序——用函数实现交换a,b的值,这道题对于你们来说应该很简单,但是如果不熟悉指针的人可能会写出下面的代码:

#include 
void swap(int x, int y);
int main()
{
	int a = 1;
	int b = 2;
	swap(a, b);
	printf("a=%d\n", a);
	printf("b=%d\n", b);
	return 0;
}
void swap(int x, int y)
{
	int t = x;
	x = y;
	y = t;
}

乍一看好像没什么问题是吧?但是将程序运行起来,我们将会得到以下结果 :

 可以看到,a,b的值并没有实现交换,所以为什么没有写成函数时一切正常,但是一使用函数就没办法交换了呢?

其实是因为函数在被调用的时候,形参是被临时创建的,一旦出了函数,它们就会被销毁。运行函数时将a,b的值赋给了x,y,实现了x,y的值的交换,然后函数调用结束,x,y就死了,本质上并没有对a,b造成任何影响。

由此可见,我们急需一个东西使得函数能够与实参建立联系,于是c语言就引入了指针,指针可以访问到想要访问的变量的地址,从而敲开变量家的门,交换两个变量家里的人。(是不是有点像高位者对低位者行使权力,形参和实参等级相同,都是int类型,所以无法通过该形参去改变实参)通过指针,我们就可以通过函数改变实参的值,所以将交换两数的值的代码进行改造:

#include 
void swap(int* x, int* y);  //
int main()
{
	int a = 1;
	int b = 2;
	swap(&a, &b);            //
	printf("a=%d\n", a);
	printf("b=%d\n", b);
	return 0;
}
void swap(int* x, int* y)    //
{
	int t = *x;              //
	*x = *y;                 //
	*y = t;                  //
}

结果就可以正确了 。

 我将所有有变化的地方都用//进行标出,就会发现两个新的符号——“ * ”,“ & ”。

1.2 指针的相关符号 —— * ,&

 取地址操作符(&)

在C语⾔中创建变量其实就是向内存申请空间,内存里面的每一个空间都有它们自己的地址,就像每一个人的家都有独一无二的坐标一样,家就是内存空间,而坐标就是地址,一个变量住进一个家,也就有了一个地址,而“&”(取地址操作符)就是可以获取变量地址的操作符。

例如:&a就获得了a的地址

地址表示

32位机器有32根地址总线(还有64位机器,这里以32位平台举例),每根线只有两态,表⽰0,1(电脉冲的有⽆),那么⼀根线,就能表⽰2种含义,2根线就能表⽰ 2x2=4 种含义,依次类推。32根地址线,就能表⽰2^32种含义,每一种含义就代表着一个地址,

我们知道,一个字节有8个比特位,所以存储一个地址就需要用32/8=4个字节(也就是一个指针的大小,因为指针存放的就是变量的地址)。

解引用操作符(*)

其实操作符“ * ”有两个用途:

1.定义一个指针变量

int a;是定义了一个整型的变量a。

int* b;就是定义了一个指向整型变量的指针。

b=&a;b就得到了a的地址

 有多少不同类型的变量,就可以有对应不同类型的指针。char* a,double* a 等等。但是指针的类型必须和变量类型一一对应!因为不同类型的指针访问的权限不同,char*类型的指针解引用(就是下面的第二个用途)后只能访问char类型对应的一个字节,int*类型也是一样。

2.获取指针所指向变量的值(解引用)

int a=5;//定义变量a
int* p=&a;//p得到a的地址
*p=10;//通过解引用改变a的值

p得到a家的地址还不够,想要改变a的值就要通过“ * ”来进入a的家来改变a的值。

1.3指针+-整数

指针+-整数代表着指针指向位置的移动,移动的多少与指针类型有关(这也是指针类型与变量类型要一一对应的原因),char*类型指针+1代表跳过内存中的一个字节,指向下一个字节的地址,int*类型就是四个字节

要注意,在指针类型中有⼀种特殊的类型是 void* 类型的,可以理解为无具体类型的指针(或者叫泛型指针),这种类型的指针可以用来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进行指针的+-整数和解引用的运算,因为不知道要跳过几个字节。

1.4 const修饰指针变量 

我们知道变量是可以修改的,如果把变量的地址交给⼀个指针变量,通过指针变量的也可以修改这个变量,但是一旦这个指针变量用const修饰了(如:const char* p)编译器就不允许改变该指针存放的地址里面的值了!

 

1.5 野指针 

所谓野指针就是没有明确指向的指针,它的成因有以下几种 :

1.指针未初始化

int main()
{
    int *p;//局部变量指针未初始化,默认为随机值
    *p = 20;
    return 0;
}

2.指针越界访问

int main()
{
    int arr[10] = {0};
    *p = &arr[0];
    int i = 0;
    for(i=0; i{1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7}};
    test(arr, 3, 5);
    return 0;
}

文章版权声明:除非注明,否则均为VPS857原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复:表情:
评论列表 (暂无评论,0人围观)

还没有评论,来说两句吧...

目录[+]

取消
微信二维码
微信二维码
支付宝二维码