【C语言】初识C语言(下篇)

简介: 【C语言】初识C语言(下篇)

大家好,这里是anduin.今天将给大家带来初识C语言的最后一部分,和之前一样点到为止,适当补充,今天的内容是#define 定义常量和宏、指针和结构体三部分内容,事不宜迟,我们这就开始。



12. #define 定义常量和宏


定义标识符常量


我们在之前常量那一部分就认识到#define可以定义常量,凡是用到常量的地方都可以用define定义的宏来替换。

#include<stdio.h>
//#define 定义标识符常量
#define MAX 1000//定义整形
#define STR "abcdef"//定义字符串
int main()
{
     printf("%d\n",MAX);
     int a = MAX;
     int arr[MAX] = {0}; 
     printf("%d\n",a);
     printf("%s\n",STR); 
     return 0; 
}

分析:如代码所示,#define用来定义常量MAX,当对变量a进行赋值时,可以打印出1000,同样的对于数组arr的数组元素为MAX,也就是1000个,由于MAX为常量,所对应arr中的元素也就是1000个(如下图),对于字符串常量STR也是相同的原理。


3613d5771ce04c4ea4c93233dc800433.png


定义宏


如果我们平时实现两个数相加的程序,我们可以直接在main函数中实现,或者是封装一个函数,代码如下:

#include<stdio.h>
//函数实现
int Add(int x,int y)
{
    return x+y;
}
int main()
{
    int a = 10;
    int b = 20;
    int c = Add(a,b);
    printf("%d\n",c);
}


那么除了函数,可不可以用其他方法实现呢?有,就是我们所说的宏:

#include<stdio.h>
#define ADD(x,y) ((x)+(y))
int main()
{
    int a = 10;
    int b = 20;
    int c = ADD(a,b);
    printf("%d\n",c);
    return 0;
}



对比:我们可以看到对于这两种实现方式,他们俩是很像的,就如函数有函数体,宏也有宏体(((x)+(y))),虽然他们比较相似,但是他们也有着许多差别!!!(仅目前所学知识归纳,不全)


   宏和函数的差别:

       实现时有差异,定义时有差异(实现:函数实现时是调用函数,而宏是预处理指令;定义:函数有返回值类型,函数返回值,函数体,函数名,形参等等而宏则十分简单)

       宏的参数没有类型,函数的参数有类型(代码可以看到形参的类型,和宏的无类型)

       函数体 - 宏体

       函数传实际参数,宏直接起替换作用(如代码中就是a,b就是直接替换宏中的x,y)



13. 指针


内存

   众所周知,内存是电脑上特别重要的存储器,它是外存与CPU进行沟通的桥梁,计算机所有程序的运行都在内存中进行,当计算机没有出现寄存器和高速缓存区之前,计算机都是要从内存中调取数据到CPU中进行运算,内存的重要性可见一斑。


   所以内存的使用效率也是要被有效划分的,我们把内存单元划分成一个个小小的内存单位,每个内存单位单位大小是一个字节,如下图所示:


b1c356e707714a95ab64a56524b0898c.png


但是访问内存单元又成了一个问题,我们在查找货物时需要给货物编号,在拜访别人家时需要借助地址,在C语言中也一样,为了能有有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号就被称为该内存单元的地址。但是地址在平时说起来比较拗口,所以我们把给他起了个好听的名字  - 指针。



指针的分析


&操作符

#include<stdio.h>
int main()
{
    int a = 10;
    int *pa = &a;//指针变量pa
}

分析:我们知道,int类型a变量的大小是4个字节,我们启动调试,点击内存窗口&a,并将其内存显示一列,观察它的地址发现,因为a占用4个字节,每个字节都有一个地址,在内存中它们地址是逐次增大的,与之对应的a的地址与a中第一个字节所存放的地址是相同的,也就是说&a取出的是第一个字节的地址。

833acce4b1aa4731a841d2c21729e140.png



指针和指针变量


地址取出来了,那么用什么保存呢?指针变量。

分析:pa是创建出来存放地址的,这个变量就是指针变量,他们通常写成int *p,char *p等形式,而int *整体是一个类型,叫做整形指针类型*说明pa是指针变量,而int说明pa指向的对象是int类型我们口头语上说的指针一般指的是指针变量!)


7108221ac24e462baf6489e26a76b86f.png



*操作符与指针的关系


那么问题来了,生活中我们拿到一户人家的地址时,可以找到他家并去拜访他,那么指针是否也可以起到这种效果呢?

当然可以!这时候就要用到我们上次没讲的*解引用操作符

#include<stdio.h>
int main()
{
    int a = 10;
    int *pa = &a;
    *pa = 20;
    printf("%d\n",a);
    //*&a;//也就是找到地址在拿数据,相当于就是a
}


分析:*操作符其实就是起到一个间接访问的作用,*pa的意思其实就是通过pa中存放的地址,找到pa指向的空间,拿到空间里的数据,也就相当于a = 20,使用*操作符也就起到了"拜访"数据的作用。

与&操作符结合理解就是&操作符是你找到地址,*则是找到数据,一个是来,一个是去。

Tips:可能大家有些疑惑,解引用操作符会不会和乘号混淆?我可以明确地告诉你:不会!

因为解引用操作符*是单目操作符的缘故,并不会和双目操作符乘*所混淆的。



指针变量的大小


计算及其结果


那么指针变量的大小又是多少呢?让我们用sizeof来计算一下。

由于pc是指针变量,而它是char*字符指针类型的,所以用计算大小时用pc和用它的类型本质上是一样的,通过类型来计算大小还是计算它的变量大小是一样的。

#include<stdio.h>
int main()
{
    char ch = 'a';
    char* pc = &ch;
    printf("%d\n", sizeof(char *));
    printf("%d\n", sizeof(short *));
    printf("%d\n", sizeof(int *));
    printf("%d\n", sizeof(long *));
    printf("%d\n", sizeof(long long *));
    printf("%d\n", sizeof(float *));
    printf("%d\n", sizeof(double *));
    return 0;
}

138867b760e14b88a65ba7b4ab562adb.png



解释


   指针变量是用来存放地址的,其大小取决于一个地址需要多大的空间,我们的电脑是硬件,在电脑中有一层地址线(32/64位)。

   电线上通电后,转化为1/0组成的数字信号(如图),这些地址组合有2的32次方个,而在这些地址也就是32位的由01组成的地址序列,每个1/0就占一个bit位,每8个bit位构成一个字节,所以地址存放起来的大小总共就是4个字节,而指针变量就是存放地址的,那么它的大小也就是4个字节!!!当然在64位平台上地址序列就是64个1/0组成的二进制序列,存起来就需要八个字节。



e1c8a318d2f444fb846ea17bb6e702c8.png



14. 结构体


概念


在C语言中存在着许多类型,但是他们所表示的往往是部分数据,并不能通过一个类型来描述生活中的一个事物,例如一本书:他们要有书名+定价+作者等组成,这些复杂对象不能简单地使用单一类型进行描述的,在C语言中可以用结构体来描述这种复杂对象


使用方法


第一种访问方式

#include<stdio.h>
//结构体类型
struct Book
{
     char bookname[30];
     float price;
     char writer[20];  
};
int main()
{
     struct Book s = {"chushiclanguage",1.01,"anduin"};//创建变量并初始化
     //结构体变量.结构体成员
     printf("%s %f %s\n",s.bookname,s.price,s.writer);   
}

对创建结构体类型及其变量初始化的分析:

如代码,首先创建结构体类型Book,在其内部创建bookname,price,writer等类型选项,再在main函数中定义结构体变量s,通过大括号的方式对其内容进行初始化。

.访问操作符就是通过结构体变量.结构体成员的形式,对结构体内容进行访问,运行代码输出结果为:


a1675c56074d477d8a6cb18ecd110965.png


第二种访问方法

#include<stdio.h>
struct Book
{
    char bookname[30];
    float price;
    char writer[20];
};
void Print(struct Book* ps)
{
    printf("%s %.2f %s\n", ps->bookname, ps->price, ps->writer);
    //结构体指针->结构体成员
    //printf("%s %.2f %s\n", (*ps).bookname, (*ps).price, (*ps).writer);
}
int main()
{
    struct Book s = { "chushiclanguage",1.01,"anduin" };//创建变量并初始化
    Print(&s);
}


分析:从上面那段代码可以知道.操作符可以访问,那么可不可以用另外一种方式来访问呢?

1.(.)指针方式访问

如代码所示,定义Print函数,参数为s的地址,在函数中我们仍然是通过.操作符的方式来进行访问,传参传的是地址,有结构体指针ps进行保存,再通过*符号来找到结构体变量s,并通过.操作符进行访问。

2.->方式访问

由于参数是结构体指针,便可以通过->来进行访问,格式为结构体指针->结构体成员,这样也可以进行访问。


结构体数据输入方法


我们平常想要输入数据时,经常要用到scanf函数,那么对于结构体我们如何输入数据呢?

#include<stdio.h>
struct Book
{
    char bookname[30];
    float price;
    char writer[20];
};
int main()
{
    struct Book s;
    scanf("%s %f %s",s.bookname,&(s.price),s.writer);
    printf("%s %.2f %s\n",s.bookname,s.price,s.writer);
}

71f7b1bc931d4f07a55d03675d180997.png


Tips:这里的bookname,writer是数组名,数组名本来就是地址,所以不需要&,而price是浮点型,那就需要取地址了!!!



结语


好了,以上就是初识C语言的全部内容,对于C语言中的知识点,我们也都有了一个初步的了解,对于其深度理解,我会在之后的博文中一一剖析。


相关文章
|
Linux Windows
Linux tar/rpm/yum命令软件安装
Linux tar/rpm/yum命令软件安装
868 2
|
数据库 数据安全/隐私保护 Android开发
微信聊天记录导出为电脑txt文件教程
本文的最终目的是将手机微信的聊天记录导出到电脑里,变成txt文本文件,然后对其进行分析。 网上有一些工具也可以完成这个功能,但是基本都是付费的。手动操作的话,找了很多的博客,基本没有完全有效的。最终找到一篇很靠谱的教程:传送门,本文基本参考这篇进行整理。首先上我的github把所有需要的文件下载下来:https://github.com/godweiyang/wechat-explore,用法稍后说明。
3919 0
微信聊天记录导出为电脑txt文件教程
|
Web App开发 SQL 流计算
常见的浏览器内核
常见的浏览器内核
|
机器学习/深度学习 自然语言处理 Linux
hisper 在 Linux 中的应用,以及如何利用它来实现高效的自动语音识别
【6月更文挑战第7天】本文探讨了Whisper,一个基于Linux的先进自动语音识别(ASR)系统,它使用PyTorch构建,支持多语言识别。在Linux环境下,通过安装依赖、下载代码、配置环境变量及编译安装,可实现Whisper的部署。Whisper以其多语言支持、高准确性和实时性,适用于语音助手、翻译等场景。随着技术发展,Whisper有望在更多领域发挥作用。
350 5
|
10月前
|
运维 自然语言处理 Linux
OS Copilot 首次使用体验
OS Copilot是阿里云推出的一款基于大模型的Linux系统智能助手,支持自然语言问答、命令辅助执行和系统调优等功能。通过CHAT、CODEGEN、CODESUM三种模式,用户可以更高效地解决日常问题、生成代码及进行代码分析。安装简便,只需三步:申请云主机、创建权限角色、安装Copilot。新功能如-t、-f参数及管道操作简化了任务处理,极大提升了Linux系统的使用效率。对于开发者和运维人员来说,OS Copilot是一个强大的工具,尤其在国产操作系统上的应用前景广阔。
|
移动开发 前端开发 JavaScript
html5 Canvas 绘制基本图形 从直线图形到使用路径 - 直线、矩形、路径、多边形、复杂组合图形
html5 Canvas 绘制基本图形 从直线图形到使用路径 - 直线、矩形、路径、多边形、复杂组合图形
364 0
html5 Canvas 绘制基本图形 从直线图形到使用路径 - 直线、矩形、路径、多边形、复杂组合图形
|
小程序 JavaScript 安全
【微信小程序-原生开发】转发给好友/群,分享到朋友圈(含单页模式访问云开发数据库的方法)
【微信小程序-原生开发】转发给好友/群,分享到朋友圈(含单页模式访问云开发数据库的方法)
552 0
|
传感器 数据采集 IDE
Sensor Shield V5.0
Sensor Shield V5.0是一款Arduino扩展板,它提供了多个数字和模拟信号输入输出接口,可以方便地连接和控制各种传感器和执行器。
1766 1
|
开发工具 Android开发 数据安全/隐私保护
AppsFlyer 研究(十四)创建 Facebook App 获取FaceBook App ID
AppsFlyer 研究(十四)创建 Facebook App 获取FaceBook App ID
902 0
|
存储 弹性计算 运维
阿里云无影云桌面价格_云电脑具体收费表
阿里云无影云桌面价格_云电脑具体收费表,阿里云无影云电脑配置具体价格表,无影云桌面4核8G企业办公型云电脑可以免费使用3个月,无影云电脑地域不同价格不同,无影云电脑价格是由云桌面配置、云盘价格、互联网访问带宽价格、AD Connector 价格、桌面组共用桌面session 价格等费用组成,阿里云百科分享阿里云无影云电脑配置具体价格表
575 0