C语言教程指针笔记整理

news2024/11/24 0:30:33

https://www.bilibili.com/video/BV1cx4y1d7Ut?spm_id_from=333.788.videopod.episodes&vd_source=e8984989cddeb3ef7b7e9fd89098dbe8&p=107
本篇为贺宏宏老师C语言教程指针部分笔记整理

//.c文件

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <ctype.h>

//8-1 什么是指针
//指针:就是地址!
//指针:就是地址!
//指针:就是地址!

int main()
{
    int a = 10; //4个字节    
    int b = 20;

    &a; //获取a的地址
    &b; //获取b的地址

    //printf("a的地址=%p,b的地址=%p\n",&a,&b);//%p:输出地址(指针),以16进制进行输出
    printf("a的地址=%d,b的地址=%d\n",&a,&b);

    return 0;
}

// 8-2 指针变量

int main()
{
    int a = 10;
    int b = 20;
    int *p = &a; //一个int地址(指针)赋值给一个int指针变量
    //获取a的地址,int &p = &a;(int &p C++引用) int *p = &a;
    p = &b; //把b的地址赋值给p //此处不能用*p了,*p的含义是引用,一词多义
    char c;
    double d;
    char *p1 = &c;
    double *p2 = &d;//指针的类型要根据变量的类型进行匹配
    return 0;
}

// 8-3 使用指针变量

int main()
{
    int a = 10;

    printf("%d,%d\n",a,&a);//a的值,a的地址
    int *p = &a;
    printf("%d,%d,%d\n",*p,p,&p);//p指向的变量a的值,a的地址,p的地址

    return 0;
}

// 8-4 &的多个作用
// &的作用:1.按位与 例如4&3 2.取地址 例如 &a 3.C++的引用
//&变量名:获取该变量的地址(指针),&:取地址符(号);这里的&是个单目运算符
//4&3:按位与,这里的&是个双目运算符,有两个变量

int main()
{
    int a = 10;
    int b = 20;
    int c = 4 & 3;//按位与 100 & 011 = 000

    printf("%d\n",c);
    printf("%p,%p,%p\n",&a,&b,&c);
    printf("%p,%p,%p\n",&a&b);//按位与

    int& d = a;//C++的引用,相当于a有一个别名叫d了;与其他两种用法的不同在于这个&前面有数据类型

    return 0;
}

//8-5 指针应用(指针最重要的部分) Swap交换数据(两个错误示例)

//交换两个变量的值(写成函数)

void Swap_err1(int a, int b)//没有交换成功,错误
{
    int tmp = a;
    a =  b;
    b = tmp;
    printf("%d %d",&a,&b);
}

void Swap_err2(int *p1, int *p2)//没有解引用,交换失败
{
    int *tmp = p1;
    p1 = p2;
    p2 = tmp;
}

在这里插入图片描述

//8-6 指针应用 Swap交换数据2
//总结:一个函数A通过调用函数B,来修改A中变量的值:
//: 1.必须传指针; 2.B中必须解引用

void Swap(int *p1,int *p2)
{
    int tmp;
    tmp = *p1;
    *p1 = *p2;
    *p2 = tmp;
}

int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%d %d",&a,&b);
    printf("交换前=%d,%d\n",a,b);

    Swap(&a,&b);//交换a,b两个值

    printf("交换后=%d,%d\n",a,b);
    return 0;
}

在这里插入图片描述

// 8-7 通过指针返回多个值
//C语言怎么返回两个值?

double Fun(int a, int b, int c)
{
    int d = b * b - 4 * a * c;
    double x1, x2;
    x1 = (-b + sqrt(d))/(2 * a);
    x2 = (-b - sqrt(d))/(2 * a);

    return x1; // C语言一般只能返回0个或1个值
}


double Fun(int a, int b, int c, double *x1,double *x2)
{
    int d = b * b - 4 * a * c;
    double x1, x2;
    *x1 = (-b + sqrt(d))/(2 * a);
    *x2 = (-b - sqrt(d))/(2 * a);

    return 2; //2个根
}

int main()
{
    double x1;
    double x2;
    Fun(4,5,1,&x1,&x2);
    printf("%lf,%lf\n",x1,x2);

}

//8-9 指针指向数组元素
//问题1:指针如何指向这个数组的元素

//问题2:arr名字
//一维数组arr的名字arr表示整个数组只在如下情况:
//1.在定义数组的同一个函数中求sizeof.例如int arr[10]; sizeof(arr) -> 40,因为int是4个字节
//2.在定义数组的同一个函数中&arr+1表示&arr的地址加一整个数组的大小,例如int arr[10],&arr,&arr+1 = &arr+40
//其他情况,arr都表示数组的起始地址

int main()
{
    int arr[10] = {1,3,5,7,9,11,13,15,17,19}; 
    
    //int* p = &arr[0];//第一个元素int的地址
    int *p = arr;//和上一行等价

    printf("%d,\n%d\n",*p,arr[0]);
    printf("%d,\n%d,\n%d\n",&arr,sizeof(arr),&arr+1);

    return 0;
}

//8-10 指针的加法运算
//指针的算数运算:前提是这个指针指向一个数组,同时程序应该保证不越界
//p+整数,p++,++p合法

int main()
{
    int arr[10] = {1,3,5,7,9,11,13,15,17,19};
    
    //int* p = &arr[0];//第一个元素int的地址
    int *p = arr;//和上一行等价
    printf("%d ",*p);

    //通过指针输出(访问)数组的所有元素
    for(int i = 0; i < 10; i++, p++)
    {
        printf("%d ",*p);
    }
    return 0;
}

//8-11指针的减法运算
//指针的算数运算:前提是这个指针指向一个数组,同时程序应该保证不越界
//p+整数,p++,++p合法

int main()
{
    int arr[10] = {1,3,5,7,9,11,13,15,17,19};
    
    //int* p = &arr[0];//第一个元素int的地址
    int *p = &arr[9];//和上一行等价
    int num = sizeof(arr);
    printf("%d\n",num); // sizeof(arr)可是40哦,不是10哦,因为int表示4个字节哦。
    for(int i = 0; i < 10; i++)//所以这里不能写成i < sizeof(arr),这样就循环40次了。超过10就越界,要出错了
    {
        printf("%d ",*p--);
    }
}

//8-12通过指针引用数组元素

int main()
{
    int a[10];
    int i;
    int *p = a;
    printf("please enter 10 integer numbers:");
    for(i = 0; i < 10; i++)
        scanf("%d", &a[i]);
    for(i = 0; i < 10; i++)
        printf("%d ",a[i]);
    printf("\n");
    return 0;
}

//8-13 指针的关系运算
//<,> >= , <=, !=,前提是必须指向同一个数组,绝对不可以操作不同的数组

// 错误用法:在不同的数组了,返回值为0

int main()
{
    int a = 10;
    int b = 20;
    int *p = &a;
    printf("%d\n",*(p+1));//错误的应用
    int *q = &b;
}

//从头到尾输出数组

int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    
        for(int *p = arr;p!= &arr[10];p++)//标准规定可以使用尾后(尾巴的后面:此处是指数组最后一位的下一处地址)地址(指针)
            printf("%d ",*p); //输出1 2 3...
    //或者
    /*
        for(int *p = arr; p != &arr[10]; p++)
            printf("%d ",*p);    
    */

    //或者
    /*
        for(int *p = arr; p <= &arr[9]; p++)
            printf("%d ",*p);    
    */
      return 0;
}

//8-15 指针在数组中的错误应用
//常见的错误:越界错误

int main()
{
    int a[10];
    int i;
    int *p;
    p= a;
    printf("please enter 10 integer numbers:");
    
    for(i = 0; i < 10; i++)
        scanf("%d", p++); //这里p的指针已经到数组的最后了(p已经到达a的尾后指针),改进办法:p = a;(把p重新赋值),下一行
    
    p = a;
    
    for(i = 0; i < 10; i++,p++)//这里p指针再往后就不是数组内的数了,就是空的地方了,输出的数为随机的数值
        printf("%d ",*p);
    printf("\n");
    return 0;
}

8-16
//8-16 数组作为参数传递:数组名仅仅表示数组首元素的地址
//传数组名+数组长度

//示例1.输出数组的所有元素
//p:数组的起始地址,n:元素的个数

void Show (int *p, int n)
{
    for(int i = 0; i < n; i++)
    {
        printf("%d ",p[i]);
    }
}

int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    Show(arr,sizeof(arr)/sizeof(arr[0]));//数组元素个数=数组长度/数组每一个元素的长度(这里用第一个元素的长度指代了)
    return 0;
}

//示例2.将数组a中n个整数按相反顺序存放

void inv(int *x, int n) //x数组的起始地址,n元素个数
{
    int tmp;
    //把x当作数组名来操作:(更推荐使用这种方法)
    
    // for(int i = 0, j = n-1; i < j; i++, j--)//i往后走,j往前走
    // {
    //     tmp = x[i];
    //     x[i] = x[j];
    //     x[j] = tmp;
    // }
    

    //把x当作指针来操作:
    for(int i = 0, j = n-1; i < j; i++, j--)
    {
        tmp = *(x+i);
        *(x+i) = *(x+j);
        *(x+j) = tmp;
    }    

}

void Show (int *p, int n)
{
    for(int i = 0; i < n; i++)
    {
        printf("%d ",p[i]);
    }
}

int main()
{
    int arr[] = {1,3,5,7,9,11,13,15,17,19};
    inv(arr,sizeof(arr)/sizeof(arr[0]));
    Show(arr,sizeof(arr)/sizeof(arr[0]));
    return 0;
}

把x当作数组名来操作:
在这里插入图片描述
把x当作指针来操作:
在这里插入图片描述

示例3
在这里插入图片描述
5个数字至少需要4次遍历:

第一次:
将第一个数字与剩下的最小值进行比较:
如果第一个数字小于剩下数字的最小值,顺序不变;
如果第一个数字大于剩下数字的最小值,将剩下数字的最小值与第一个数字进行交换。

第二次:
将第二个数字与剩下的最小值进行比较:
如果第二个数字小于剩下数字的最小值,顺序不变;
如果第二个数字大于剩下数字的最小值,将剩下数字的最小值与第二个数字进行交换。

第三次:
将第三个数字与剩下的最小值进行比较:
如果第三个数字小于剩下数字的最小值,顺序不变;
如果第三个数字大于剩下数字的最小值,将剩下数字的最小值与第三个数字进行交换。

第四次:
将第四个数字与剩下的最小值进行比较:
如果第四个数字小于剩下数字的最小值,顺序不变;
如果第四个数字大于剩下数字的最小值,将剩下数字的最小值与第四个数字进行交换。

第五次:
将第五个数字与剩下的最小值进行比较:
如果第五个数字小于剩下数字的最小值,顺序不变;
如果第五个数字大于剩下数字的最小值,将剩下数字的最小值与第五个数字进行交换。

//示例3.用指针方法对10个整数按由大到小顺序排序(选择排序法)

//选择法排序:每次从待排序的数中找最小值和待排序的第一个值进行交换,直到全部有序
//arr:数组起始地址,n:元素个数

//下标法。优先推荐使用下标法,指针法容易出错

void SelectSort1(int* arr, int n)
{
    int k;
    int tmp;
    for(int i = 0; i < n-1; i++)
    {
        k = i;//这里要提前给k赋值一下
        for(int j = i+1; j < n; j++)
        {
            if(arr[j] < arr[k]) //指针方式:*(arr+j) < *(arr+k)
            {
               k = j; 
            }
        }
        if(arr[k] != arr[i])//这里写k!=i就行了
        {
            tmp = arr[i];//指针方式:*(arr+i)
            arr[i] = arr[k];//指针方式:*(arr+i) = *(arr+k)
            arr[k] = tmp;//指针方式:*(arr+k) 
        }
    }
}

//指针方式:

void SelectSort(int* arr, int n)
{
    int k;
    int tmp;
    for(int i = 0; i < n-1; i++)
    {
        k = i;//这里要提前给k赋值一下
        for(int j = i+1; j < n; j++)
        {
            if(*(arr+j) < *(arr+k))
            {
               k = j; 
            }
        }
        if(k != i)
        {
            tmp = *(arr+i);
            *(arr+i) = *(arr+k);
            *(arr+k)  = tmp;
        }
    }
}

void Show (int *p, int n)
{
    for(int i = 0; i < n; i++)
    {
        printf("%d ",p[i]);
    }
}

int main()
{
    int arr[] = {10,3,65,7,69,181,193,15,157,19};
    Show(arr,sizeof(arr)/sizeof(arr[0]));
    printf("\n");
    SelectSort(arr,sizeof(arr)/sizeof(arr[0]));
    Show(arr,sizeof(arr)/sizeof(arr[0]));
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2244892.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从二维到一维:动态规划矩阵问题的优化之道

动态规划中的矩阵问题是非常经典的应用场景&#xff0c;比如最小路径和问题。这类问题很自然地可以想到使用二维 dp 数组来求解。 我们定义&#xff1a; dp[i][j] 表示从矩阵的第 i行第 j列到右下角的最小路径和。 基本解法 求解过程从右下角开始&#xff0c;向左上角遍历&am…

git,ssh免密公钥配置,gitee为例,GitHub,gitlab同理

git&#xff0c;ssh免密公钥配置&#xff0c;gitee为例&#xff0c;视频教程在这 git&#xff0c;ssh免密公钥配置&#xff0c;gitee为例&#xff0c;GitHub&#xff0c;gitlab同理_哔哩哔哩_bilibili 一、进入.ssh目录 cd ~/.ssh 二、查看是否有id_rsa.pub这个文件 分为…

Spring Boot整合Kafka,实现单条消费和批量消费,示例教程

如何安装Kafka&#xff0c;可以参考docker搭载Kafka集群&#xff0c;一个文件搞定&#xff0c;超简单&#xff0c;亲试可行-CSDN博客 1、在pom.xml中加入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-sta…

基于Vue+SpringBoot的求职招聘平台

平台概述 本平台是一个高效、便捷的人才与职位匹配系统&#xff0c;旨在为求职者与招聘者提供一站式服务。平台内设三大核心角色&#xff1a;求职者、招聘者以及超级管理员&#xff0c;每个角色拥有独特的功能模块&#xff0c;确保用户能够轻松完成从信息获取到最终录用的整个…

FPGA FIFO系列 - FIFO使用中需要注意的若干问题

FIFO使用中需要注意的若干问题 文章目录 FIFO使用中需要注意的若干问题前言场景1&#xff1a;包数据FIFO设计之冗余法场景2、FIFO数据传输之流控总结 前言 场景1&#xff1a;包数据FIFO设计之冗余法 场景&#xff1a;类似图像、文字等码流数据是不需要重复被访问的&#xff0c…

.NET 9 - BinaryFormatter移除

1.简单介绍 .NET 9 SDK正式版已经发布, 下载地址是.NET9 同时.NET Conf 2024 大会已经从2024-11-13开始了&#xff0c;感觉Aspire和AI的内容相对挺多的&#xff0c;主题分享演示时候打开的网站大部分都是Blazor制作的。 这次.NET Conf 2024老师也再次说明了一下&#xff0c;…

[免费]SpringBoot+Vue毕业设计论文管理系统【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue毕业设计论文管理系统&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue毕业设计论文管理系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 现代经济快节奏发展以及不断完善升级的信…

C# 高级--反射 详解

一、反射是什么 1、C#编译运行过程 高级语言->编译->dll/exe文件->CLR/JIT->机器码 2、原理解析metadata&#xff1a;元数据数据清单&#xff0c;记录了dll中包含了哪些东西,是一个描述。IL&#xff1a;中间语言&#xff0c;编译把高级语言编译后得到的C#中最真…

OpenCV与AI深度学习|16个含源码和数据集的计算机视觉实战项目(建议收藏!)

本文来源公众号“OpenCV与AI深度学习”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;分享&#xff5c;16个含源码和数据集的计算机视觉实战项目 本文将分享16个含源码和数据集的计算机视觉实战项目。具体包括&#xff1a; 1. 人…

【软考网工笔记】网络基础理论——应用层

TLv 基本编码规则&#xff08;BER&#xff09;将ASN.1表示的抽象类型值编码为字节串&#xff0c;这种字节串的结构为&#xff1a;类型——长度——值&#xff0c;简称TLv。 其中&#xff0c;值部分还可以递归的在编码为TLv结构&#xff0c;一具有表达复杂结构的能力。 IP地址…

用Python爬虫“偷窥”1688商品详情:一场数据的奇妙冒险

引言&#xff1a;数据的宝藏 在这个信息爆炸的时代&#xff0c;数据就像是一座座等待挖掘的宝藏。而对于我们这些电商界的探险家来说&#xff0c;1688上的商品详情就是那些闪闪发光的金子。今天&#xff0c;我们将化身为数据的海盗&#xff0c;用Python这把锋利的剑&#xff0…

企业网络安全规划建设实践

规划是指较全面或长远的计划。凡事预则立&#xff0c;不预则废&#xff01; 在企业战略规划方面&#xff0c;随着市场环境变化速度的不断加快&#xff0c;人们越来越意识到企业战略规划对企业生存和发展的重要性&#xff0c;战略规划能帮助企业解决影响组织未来发展最重要、最…

QT基本绘图

QT绘图 1.概述 这篇文章介绍如何绘图 2.绘图基本操作 创建一个普通的widget类型的项目 在widget.h 文件中重写绘图事件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : p…

Linux驱动开发(7):使用设备树实现RGB 灯驱动

通过上一小节的学习&#xff0c;我们已经能够编写简单的设备树节点&#xff0c;并且使用常用的of函数从设备树中获取我们想要的节点资源。 这一小节我们带领大家使用设备树编写一个简单的RGB灯驱动程序&#xff0c;加深对设备树的理解。 1. 实验说明 本节实验使用到 EBF6ULL-…

MATLAB实现GARCH(广义自回归条件异方差)模型计算VaR(Value at Risk)

MATLAB实现GARCH(广义自回归条件异方差)模型计算VaR(Value at Risk) 1.计算模型介绍 使用GARCH&#xff08;广义自回归条件异方差&#xff09;模型计算VaR&#xff08;风险价值&#xff09;时&#xff0c;方差法是一个常用的方法。GARCH模型能够捕捉到金融时间序列数据中的波…

Neo4j下载及其Cypher语法介绍

1.部署安装 Neo4j支持众多平台的部署安装&#xff0c;如&#xff1a;Windows、Mac、Linux等系统。Neo4j是基于Java平台的&#xff0c;所以部署安装前先保证已经安装了Java虚拟机。 在神领物流项目中&#xff0c;我们采用docker的方式进行安装。安装命令如下&#xff1a; dock…

【Redis】实现点赞功能

一、实现笔记点赞 使用redis实现点赞功能&#xff0c;对于一个笔记来说&#xff0c;不同用户只能是点赞和没点赞&#xff0c;点赞过的笔记再点击就应该取消点赞&#xff0c;所以实际上根据需求&#xff0c;我们只需要将点赞的数据存到对应的笔记里&#xff0c;查看对应的笔记相…

开源TTS语音克隆神器GPT-SoVITS_V2版本地整合包部署与远程使用生成音频

文章目录 前言1.GPT-SoVITS V2下载2.本地运行GPT-SoVITS V23.简单使用演示4.安装内网穿透工具4.1 创建远程连接公网地址 5. 固定远程访问公网地址 前言 本文主要介绍如何在Windows系统电脑使用整合包一键部署开源TTS语音克隆神器GPT-SoVITS&#xff0c;并结合cpolar内网穿透工…

【Pytorch】torch.utils.data模块

torch.utils.data模块主要用于进行数据集处理&#xff0c;是常用的一个包。在构建数据集的过程中经常会用到。要使用data函数必须先导入&#xff1a; from torch.utils import data 下面介绍几个经常使用到的类。 torch.utils.data.DataLoader DataLoader(dataset, batch_…

XGBOOST、LightGBM、CATBoost

本文介绍几种不同的 GBDT 优化算法&#xff1a; XGBoost XGBoost 对损失函数展开二阶导&#xff0c;使得提升树能逼近真是损失&#xff0c;增加正则项防止过拟合&#xff0c;XGBoost 公式&#xff1a; L( y i y_i yi​, y ^ i \hat{y}_i y^​i​): 损失函数 Ω ( f k ) \Ome…