首页 > 其他分享 >C语言 指针

C语言 指针

时间:2024-04-01 20:32:09浏览次数:22  
标签:arr int C语言 地址 pa printf 指针

目录

1.指针是什么?

2. 指针和指针类型

2.1指针的解引用

2.2指针加减整数

3.野指针

3.1 指针未初始化

3.2指针越界访问

4.指针运算

4.1指针加减整数

4.2指针减指针

4.3指针的关系运算

5.指针和数组

例1

 例2

6.二级指针

7.指针数组

8.结语


1.指针是什么?

把内存单一的编号就称为地址(地址也就叫指针)
指针其实就是地址,地址就是编号
指针就是内存单元的编号

指针变量:可以通过&(取地址操作符)取出变量的内存其实地址,把地址可以存放到一个变量中,这个变量就是指针变量

int main()
{
    int a = 10;//a是整型变量,占用4个字节的内存空间
    int* pa = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。

    //a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量 中,p就是一个之指针变量。
    //pa是一个指针变量,用来存放的地址的
    // 指针变量里边存放的是地址,而通过这个地址,就可以找到一个内存单元
    //指针是内存中一个最小单元的编号
    //本质上指针就是地址,口语中说的指针,其实是指针变量,指针变量就是一个变量,指针变量是用来存放地址的一个变量
    return 0;
}

总结:指针是用来存放地址的,地址是唯一标示一块地址空间的。

指针的大小在32位平台是4个字节,在64位平台是8个字节。

2. 指针和指针类型

指针的定义方式是: type + *

int main()
{
    char* pc = NULL;//char* 类型的指针是为了存放char类型变量的地址
    short* ps = NULL;//short* 类型的指针是为了存放short类型变量的地址
    int* pi = NULL;
    double* pd = NULL;
    printf("%zu\n", sizeof(pc));//sizeof 返回的值的类型是无符号整型 unsigned int
    printf("%zu\n", sizeof(ps));
    printf("%zu\n", sizeof(pi));
    printf("%zu\n", sizeof(pd));
    return 0;
}

指针类型的意义

2.1指针的解引用

int main()
{
    int a = 0x11223344;
    //int* pa = &a;
    //*pa = 0;
    char* pc = (char*)&a;//int*
    *pc = 0;
    //结论1:
    //指针类型决定了指针在被解引用的时候访问了几个字节
    //如果是int*的指针,解引用访问4个字节
    //如果是char*的指针,解引用访问1个字节
    //推广到其他类型
    return 0;
}

2.2指针加减整数

int main()
{
    int a = 0;
    int* pa = &a;
    char* pc =(char*) &a;
    printf("pa = %p\n", pa);
    printf("pa = %p\n", pa+1);
    printf("pc = %p\n", pc);
    printf("pc = %p\n", pc + 1);
    //结论2:
    //指针的类型决定了指针+-1操作的时候,跳过几个字节
    //决定了指针的步长
    return 0;
}

3.野指针

概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

3.1 指针未初始化

int main()
{
    int* p;
    //p没有初始化,就意味着没有明确的指向
    //一个局部变量不初始化,放的是随机值:0xcccccccc
    *p = 10;//非法访问内存了,这里的p就是野指针
    return 0;
}

3.2指针越界访问

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

如何规避野指针

1. 指针初始化

2. 小心指针越界

3. 指针指向空间释放即使置NULL

4. 避免返回局部变量的地址

5. 指针使用之前检查有效性

int main()
{
    int b = 0;
    int a = 10;
    int* p = &a;
    int* p2 = NULL;//不知道赋什么值时,就赋个NULL,表示NULL -> 0,也就和整型变量初始化赋零是一样的
    *p2 = 100;//error,0地址是无法访问的
    //如果真的想用int* p2=NULL,可以按以下方法做
    int* p3 = NULL;
    if (p3 != NULL)
    {
        *p3 = 100;
    }
    return 0;
}

4.指针运算

4.1指针加减整数

int main()
{
    int arr[10] = { 0 };
    int i = 0;
    int sz = sizeof(arr) / sizeof(arr[0]);
    //数组下标的写法
    for (i = 0; i < sz; i++)
    {
        arr[i] = 1;
    }

    int* p = arr;
    for (i = 0; i < sz; i++)
    {
        *p = 1;
        p++;
    }

    int* p = arr;
    for (i = 0; i < sz; i++)
    {
        *(p + i) = 1;
    }
    return 0;
}

4.2指针减指针

int main()
{
    int arr[10] = { 0 };
    printf("%d\n", &arr[9] - &arr[0]);
    //指针减去指针的绝对值得到的是指针和指针之间元素的个数
    //不是所有的指针都能相减
    //指向同一块空间的2个指针才能相减!
    return 0;
}

int my_strlen(char* str)
{
    char* start = str;
    while (*str != '\0')
    {
        str++;
    }
    return str - start;
}

int main()
{
    int len = my_strlen("abcdef");
    printf("%d\n", len);
    return 0;
}

4.3指针的关系运算

for(vp = &values[N_VALUES]; vp > &values[0];)

       *--vp = 0;

}

代码简化, 这将代码修改如下:

for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)

{

      *vp = 0;

}

实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证 它可行。

标准规定:

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

5.指针和数组

数组:一组相同类型元素的集合
指针变量:是一个变量,存放的是地址

例1

#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	return 0;
}

结果如下:

可见数组名和数组首元素的地址是相同的

结论:数组名表示的是数组首元素的地址。不过有两种情况除外,可以在以下文章中可见

http://t.csdnimg.cn/UrHkNicon-default.png?t=N7T8http://t.csdnimg.cn/UrHkN可以这么写代码

int arr[10] = {1,2,3,4,5,6,7,8,9,0};
 int *p = arr;//p存放的是数组首元素的地址

 例2

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	//arr 是首元素的地址
	//&arr[0]
	int* p = arr;
	//通过指针来访问数组
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%p ------- %p\n", &arr[i], p + i);
	}
	
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;
}

结果如下:

 所以p+i其实计算的是数组 arr 下标为i的地址

以下两种方式都是正确的

#include <stdio.h>
void test(int* p, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
	}
}

void test(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);//arr[i] --> *(arr+i)
	}
}

int main()
{
	int arr[10] = { 0 };
	test(arr, 10);
	return 0;
}

6.二级指针

二级指针变量是用来存放一级指针变量的地址的

int main()
{
    int a = 10;
    int* pa = &a;//pa是一个指针变量,一级指针变量
    //  *说明pa是指针,而int是在说pa指向的对象是int类型,这里指的是pa指向的a的类型是int
    int** ppa = &pa;//ppa是一个二级指针变量
    //int*在说明ppa指向的对象pa是int*类型
    //第二颗*说明ppa是指针

    **ppa = 20;

    //*pa = 20;
    printf("%d\n", *pa);
    return 0;
}

二级指针的运算

*ppa 通过对ppa中的地址进行解引用,这样找到的是 pa , *ppa 其实访问的就是 pa .

int b = 20;

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

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

**ppa = 30;

//等价于*pa = 30;

//等价于a = 30;

7.指针数组

存放指针的数组就是指针数组

int main()
{
    int a = 10;
    int b = 20;
    int c = 30;

    int arr[10];
    
    int* pa = &a;
    int* pb = &b;
    int* pc = &c;

    int* parr[10] = { &a,&b,&c };
    //parr就是存放指针的数组
    //指针数组
    int i = 0;
    for (i = 0; i < 3; i++)
    {
        printf("%d ", *(parr[i]));
    }
    return 0;
}

用指针表示二维数组

#include <stdio.h>
int main()
{
	int arr1[4] = { 1,2,3,4 };
	int arr2[4] = { 2,3,4,5 };
	int arr3[4] = { 3,4,5,6 };
	int* parr[3] = { arr1,arr2,arr3 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
			printf("%d ", parr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

8.结语

今天的经验分享就到这里,有喜欢的朋友可以点赞➕评论➕收藏➕关注,如果有不懂的地方可以咨询博主,谢谢大家支持博主!

标签:arr,int,C语言,地址,pa,printf,指针
From: https://blog.csdn.net/qq_58094522/article/details/137182980

相关文章

  • 每日一题:C语言经典例题之门禁系统
    题目描述毛毛最近要负责图书馆的管理工作,需要记录下明天读者的到访情况。每位读者有一个编号,每条记录用读者的编号来表示。给出读者的来访记录,得到每一条记录中的读者是第几次出现。输入输入的第1行包含一个整数n,表示涛涛的记录条数;第2行包含n个整数,依次表示涛涛的记录中每......
  • 菜鸟记录:c语言实现PAT甲级1010--Radix
    很长时间没做,忙于考研和实习,久违的的拾起了算法。做了很长时间,其实总体思路还是很简单的,但满分不知道为什么就是到不了,又因为网上很多答案包括柳神的都是c++,无法参透,姑且只能这样了。Givenapairofpositiveintegers,forexample,6and110,canthisequation6=110bet......
  • C语言中常用的文件操作
    本文将介绍常用的关于文件操作函数,如fopen,fclose,fread,fwrite,feek,ftell,rewind以及feof和ferror等文件操作操作函数,还介绍一些用于所有输入输出流的函数如fgetc,fputc,fgets,fputs,fprintf,fscanf等函数,还介绍了sscanf,sprintf函数,feof和ferror函数。最后介绍了文件文件缓......
  • 初识编译和链接(C语言)
    文章目录编译和链接翻译环境预处理编译汇编链接运行环境编译和链接编译和链接这两个大的过程构成了翻译环境。其实,在ANSIC的任何一种实现中,存在两个不同的环境。一个环境是翻译环境,另一个是执行环境。翻译环境中,源代码被转换为可执行的机器指令。执行环境中,代......
  • c语言实现扫雷游戏
    c语言实现扫雷游戏写在前面:呃呃呃其实是代码写完了才写的这篇文章,所以中间的测试就看不到(害,那么进入游戏首先应当是有一个菜单界面,供玩家选择开始游戏还是退出游戏,对吧菜单界面实现那么就写一个打印菜单的函数咯然后主函数部分调用一下menu(),再根据玩家的选择来判......
  • c语言例题,计算字符串长度,递归思想
    c语言中,计算字符串长度算是一个比较经典的题了,而今天我们运用两种不同的求解方法来写出不同的程序来实现计算字符串的功能。主函数 先看到主函数,主函数中设置了一串7个字符的字符串,而后面接下来定义了两个变量len1和len2,同时分别打印len1和len2,当然,打印的这两个变量其实就......
  • C语言每日一题
    1.题目2.分析这里考察的是运算符运算规则的问题,影响运算符求值顺序的主要是运算符的优先级和结合性。优先级:主要是不同优先级运算符之间的运算规则结合性:主要是优先级相同时运算符需要遵守的运算规则本题中的表达式,有以下4种运算符,它们是具有不同优先级的运算符,因此......
  • 【C语言】从零开始:用C语言实现顺序表
    欢迎来CILMY23的博客本篇主题为 从零开始:用C语言实现顺序表个人主页:CILMY23-CSDN博客C语言专栏:http://t.csdnimg.cn/hQ5a9Python系列专栏:http://t.csdnimg.cn/HqYo8上一篇C语言博客: http://t.csdnimg.cn/I4Zgf感谢观看,支持的可以给个一键三连,点赞关注+收藏。目录一......
  • 双指针妙解三数之和
    三数之和算是名气很大的算法题,我今天刚好刷到,用JavaScript实现了一下。题目如下所示:Givenanintegerarraynums,returnallthetriplets[nums[i],nums[j],nums[k]]suchthati!=j,i!=k,andj!=k,andnums[i]+nums[j]+nums[k]==0.Noticethatthesolut......
  • C语言中的基本结构3——循环结构篇
    C语言中的基本结构3——循环结构篇一、前言二、何为循环结构三、三种循环语句1.while2.do···while3.for四、循环的嵌套五、如何根据需要使用适合的循环语句?六、循环的辅助:continue和break1.continue2.break3.其余的方法:goto,return离开循环1.goto2.return七、结束语......