IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言基础总结-03 -> 正文阅读

[C++知识库]C语言基础总结-03

这篇应该是C语言基础总结的最后一篇了,讲讲最最最重要的指针

目录

指针和内存单元

指针定义和使用:

野指针:

空指针:

万能指针/泛型指针(void *):

const关键字:

修饰变量:

修饰指针:

指针和数组:

指针和数组区别:

指针++ 操作数组:

指针加减运算:

数据类型对指针的作用:

指针实现 strlen 函数(求字符数组的有效字符个数):

指针比较运算:

指针数组:

多级指针:

指针和函数:

栈 帧:

传值和传址:

指针做函数参数:

数组做函数参数:

指针做函数返回值:

数组做函数返回值:

指针和字符串:

练习:

指针和内存单元

  • 指针: 地址

  • 内存单元: 计算机中内存最小的存储单位,大小一个字节, 每一个内存单元都有一个唯一的编号。我们称这个内存单元的编号为 “地址”

  • 指针变量:存地址的变量

指针定义和使用:

int a = 10;
int *p = &a;
*p = 250; //指针的 解引用 间接引用

*p : 将p变量的内容取出,当成地址看待,找到该地址对应的内存空间

**如果做左值: 存数据到空间中**

**如果做右值: 取出空间中的内容**

任意“指针”类型大小:

指针的大小与类型无关,只与当前使用的平台架构有关。   32位:4字节   64位: 8字节

野指针:

  • 没有一个有效的地址空间的指针
int *p;
*p = 1000;
  • p变量有一个值,但该值不是可访问的内存区域
int *p = 10;
*p = 2000;
对于没有野指针,可以操作指针,但是不能通过指针操作其指向地址的元素
int *p;
p = NULL; // 这两行等价于: int *p = NULL;
if (p != NULL)
    printf(" p is not NULL");
else
    printf(" p is NULL");

重要!!!:操作指针指向的地址前一定要看指针是否有合法指向,必须要看!!!

空指针:

int *p = NULL; //#define NULL ((void *)0)

*p 时 p所对应的存储空间一定是一个 无效的访问区域

万能指针/泛型指针(void *):

可以接收任意一种变量地址。但是,在使用**【必须】**借助【强转】具体化数据类型

(注:强制类型转换:(目标数据类型)待转换变量)

char ch = 'R';
void *p; // 万能指针、泛型指针
p = &ch;
printf("%c\n", *(char *)p);

const关键字:

修饰变量:

const int a = 20;
int *p = &a;
*p = 650;
printf("%d\n", a);

修饰指针:

关于const修饰指针变量可以看我之前写的这篇文章关于const限制指针变量问题的思考,此处不再赘述

指针和数组:

数组名:

**【数组名是地址常量】**不可以被赋值 

指针是变量,可以用数组名给指针赋值

取数组元素:

int arr[] = {1, 3, 5, 7, 8};
int *p = arr;
以下几种写法结果相同:`arr[i]` == `*(arr+0) `==` p[0] `== `*(p+0)`

指针和数组区别:

1. 指针是变量。数组名为常量

2. sizeof(指针) → 4字节 / 8字节

  sizeof(数组) → 数组的实际字节数

指针++ 操作数组:

int arr[] = {1, 2, 4, 5, 6, 7, 8, 9, 0};
int *p = arr;

for (size_t i = 0; i < n; i++)
{
    printf("%d ", *p);
    p++; // p = p+1;   一次加过一个int大小 一个元素
}
p的值会随着循环不断变化,**打印结束后,p指向一块无效地址空间(野指针)**

指针加减运算:

数据类型对指针的作用:

1. 间接引用:

  决定了从指针存储的地址开始,向后读取的字节数  (与指针本身存储空间无关)

1. 加减运算:

  决定了指针进行 +1/-1 操作向后加过的 字节数

指针 * / % : error!!!

指针 +- 整数:

1. 普通指针变量+- 整数
char *p;  //打印 p 、 p+1  偏过 1 字节
short *p; //打印 p 、 p+1  偏过 2 字节
int *p;   //打印 p 、 p+1  偏过 4 字节
1. 在数组中+- 整数
short arr[] = {1, 3, 5, 8};
int *p = arr;
p + 3; // 向右(后)偏过 3 个元素
p - 2; // 向前(左)偏过 2 个元素
1. &数组名 + 1

  加过一个 数组的大小(数组元素个数 x sizeof(数组元素类型))

指针 +- 指针:

指针 + 指针: error!!!

指针 - 指针:

  1) 普通变量来说, 语法允许,无实际意义

  2) 数组来说:偏移过的元素个数

指针实现 strlen 函数(求字符数组的有效字符个数):

char str[] = "hello";
char *p = str;
while (*p != '\0')
{
    p++;
}

p-str 即为 数组有效元素的个数

指针比较运算:

  1. 普通变量来说, 语法允许。无实际意义

  2. 数组来说: 地址之间可以进行比较大小

可以得到,元素存储的先后顺序

指针数组:

一个存储地址的数组,数组内部所有元素都是地址

int a = 10;
int b = 20;
int c = 30;
int *arr[] = {&a, &b, &c}; // 数组元素为 整型变量 地址
int a[] = {10};
int b[] = {20};
int c[] = {30};
int *arr[] = {a, b, c}; // 数组元素为 数组 地址

指针数组本质,是一个二级指针

二维数组, 也是一个二级指针

多级指针:

int a = 0;

int *p = &a; 一级指针是 变量的地址

int **pp = &p; 二级指针是 一级指针的地址

int ***ppp = &pp; 三级指针是 二级指针的地址

以此类推

多级指针,不能跳跃定义!

对应关系:

ppp == &pp; 三级指针

*ppp == pp == &p; 二级指针

**ppp == *pp == p == &a 一级指针

指针和函数:

栈 帧:

当函数调用时,系统会在 stack 空间上申请一块内存区域,用来供函数调用,主要存放 形参 和 局部变量(定义在函数内部)

当函数调用结束,这块内存区域自动被释放(消失)

传值和传址:

传值:函数调用期间,实参将自己的值,拷贝一份给形参

**传址:函数调用期间,实参将地址值,拷贝一份给形参【重点!!!】**

指针做函数参数:

int swap2(int *a, int *b);
int swap2(char *a, char *b);
调用时,传有效的地址值

数组做函数参数:

void BubbleSort(int arr[10]) == void BubbleSort(int arr[])  == void BubbleSort(int *arr) 

传递不再是整个数组,而是数组的首地址(一个指针)

所以,当整型数组做函数参数时,我们通常在函数定义中,封装2个参数。一个表数组首地址,一个表元素个数

指针做函数返回值:

int *test_func(int a, int b);

指针做函数返回值,不能返回【局部变量的地址值】

数组做函数返回值:

C语言,不允许!!!!  只能写成指针形式

指针和字符串:

  • char str1[] = {'h', 'i', '\0'}; 变量,可读可写

    char str2[] = "hi"; 变量,可读可写

    char *str3 = "hi"; 常量,只读

    str3变量中,存储的是字符串常量“hi”中首个字符‘h’的地址值

    str3[1] = 'H'; // 错误!!

    char *str4 = {'h', 'i', '\0'}; // 错误!!!

  • 当字符串(字符数组), 做函数参数时, 不需要提供2个参数。 因为每个字符串都有 '\0'

这里放一个练习,直观感受下指针是怎么用的

练习:

比较两个字符串: strcmp();实现

比较 str1 和 str2, 如果相同返回0, 不同则依次比较ASCII码,str1 > str2 返回1,否则返回-1

数组方式:

int mystrcmp(char *str1, char *str2)
{
    int i = 0;
    while (str1[i] == str2[i]) // *(str1+i) == *(str2+i)
    {
        if (str1[i] == '\0')
        {
            return 0; // 2字符串一样
        }
        i++;
    }
    return str1[i] > str2[i] ? 1 : -1;
}

指针方式:

int mystrcmp2(char *str1, char *str2)
{
    while (*str1 == *str2) // *(str1+i) == *(str2+i)
    {
        if (*str1 == '\0')
        {
            return 0; // 2字符串一样
            str1++;
            str2++;
        }
    }
    return *str1 > *str2 ? 1 : -1;
}

大概就是这些,其实结构体那一块也牵扯到指针的使用,不过要是把那一块再讲了牵扯的东西有点多,有需要的可以自己去找,然后总结的这三篇可以说是C语言基础里的基础,建议好好学

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-30 11:45:05  更:2021-09-30 11:46:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 22:40:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码