【C语言】入门——指针

 

目录

 ​编辑

1.指针是什么

 2.指针类型和指针运算

2.1指针+-整数

2.2指针-指针

2.3指针的关系运算

 3.野指针

3.1野指针成因

 ?指针未初始化:

?指针越界访问:

 ?指针指向空间释放:

3.2如何规避野指针

 4.指针和数组

5.二级指针 

6.指针数组


1.指针是什么

指针,是C语言中的一个重要概念及其特点,也是C语言比较难的部分。

 ?.内存被划分成一个个的内存单元,每个内存单元的大小是1个字节

 ?.每个字节的内存单元都有一个编号,这个编号就是地址,地址在C语言中称为指针

 ?.地址要存储的话,存放在指针变量中

 ?.每个内存单元都有一个唯一的地址来标识

 ?.在32位机器上地址的大小是4个字节,所以指针变量的大小也是4个字节同理:在64位机器上地址的大小是8个字节,所以指针变量的大小也是8个字节

总结:指针就是地址,口语中说的指针通常指的是指针变量。

 2.指针类型和指针运算

 ?变量的创建可以使用不同的类型,而指针也有不同的指针类型

char  *pc = NULL;    //字符指针 
int   *pi = NULL;    //整形指针 
short *ps =NULL;    //短整型指针 
long  *pl = NULL;    //长整型指针 
float *pf = NULL;    //单精度浮点型指针
double *pd = NULL;    //双精度浮点型指针 
……

2.1指针+-整数

 ?指针类型决定了指针进行解引用操作的时候,访问几个字节

int* 访问4个字节

char* 访问1个字节

short* 访问2个字节

 ?指针类型决定了指针+1,-1跳过几个字节:

int* 的指针+1,跳过4个字节;

char* 的指针+1,跳过1个字节;

short* 的指针+1,跳过2个字节;

double* 的指针+1,跳过8个字节

总结:

指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)

比如:char* 的指针解引用就只能访问1个字节,而int* 的指针解引用能访问4个字节

int main()
{
	int n = 10;
	char* pc = (char*)&n;
	int* pi = &n;

	//打印n的地址
	printf("%pn", &n);
	
	printf("%pn", pc);
	printf("%pn", pc + 1);//打印char型跳过一个字节

	printf("%pn", pi);
	printf("%pn", pi + 1);	//打印整型指针跳过4个字节
	//0019FB40
	/*0019FB40
		0019FB41
		0019FB40
		0019FB44*/
	return  0;
}

2.2指针-指针

 ?指针-指针的前提:两个指针指向同一块区域,指针类型是相同的;

 ?指针-指针得到的是:两个指针之间的元素个数;

(如果是小地址-大地址就是负的元素个数)


		int arr[10] = { 0 };
		printf("%dn", &arr[9] - &arr[0]);	//9
		printf("%dn", &arr[0] - &arr[9]);	//-9
		//两个指针相减的前提是:指针指向的同一块连续的空间

2.3指针的关系运算

 ?标准规定:

允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。 

#define N_VALUES 5
float values[N_VALUES];
float *vp;
for (vp = &values[0]; vp < &values[N_VALUES];)
{
     *vp++ = 0; }

 3.野指针

3.1野指针成因

 ?指针未初始化:


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

?指针越界访问:


int main()
{
    int arr[10] = {0};
    int *p = arr;
    int i = 0;
    for(i=0; i<=20; i++)
   {
        //当指针指向的范围超出数组arr的范围时,p就是野指针
        *(p++) = i;
   }
    return 0;
}

 ?指针指向空间释放:

int* test()
{
	int num = 15;
	return &num;    //出了函数,这块内存就不属于我们了,还给了系统
}

int main()
{
	int* p = test();
	*p = 5;
	return 0;
}

变量num为局部变量,生命周期从创建开始到出test函数结束,test函数调用结束后num会将空间还给操作系统,此时回到主函数p的地址已经被释放,此时p就是野指针。 

3.2如何规避野指针

 ? 指针初始化

 ? 小心指针越界

 ? 指针指向空间释放即使置NULL

 ? 避免返回局部变量的地址

 ? 指针使用之前检查有效性 

 4.指针和数组

 ? 指针就是指针,指针变量就是一个变量,存放的地址,指针变量的大小是4/8

 ? 数组就是数组,可以存放一组数,数组的大小是取决于元素的类型和个数

 ? 数组的数组名是数组首元素的地址,地址是可以访问指针变量中

通过指针和数组的关系,可以利用指针的解引用访问数组的元素,不使用数组的下标。

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);

	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;
}
//输出:1 2 3 4 5 6 7 8 9 10

5.二级指针 

指针变量也是变量,是变量就有地址,所以指针变量也可以被指针存储,这个是二级指针。

int main()
{
	int a = 10;
	int* pa = &a;        //pa就是指针变量,一级指针变量,表示指针指向的a是int
	int* *ppa = &pa;    //ppa就二级指针,表示pp指向的p的类型是int*
	return 0;
}

 同样,也可以通过解引用的方式对其访问。

int b = 20;
*ppa = &b;//等价于 pa = &b;

**ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a 

**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;

6.指针数组

 ?指针数组是指针还是数组?
答案:是数组。是存放指针的数组。 

?可以利用指针数组来用一维数组模拟二维数组

int main()
{
	//用一维数组模拟一个二维数组
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };
	int arr4[] = { 4,5,6,7,8 };

	int* arr[4] = {arr1, arr2, arr3, arr4};    //用指针数组管理一维数组
	int i = 0;
	for (i = 0; i < 4; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("n");
	}

	return 0;
}

感谢你看到了这里,以上就是我对C语言指针入门的基本概括,文中不足和需要需要改善的地方望得到指点!感激不尽!!!