热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

面向数据结构的C语言基础速成宝典

前言今天上了个数据结构课,直接自闭了,记得学习C已经是去年的事了,再看语法已经忘得七七八八,所以写一篇基础知识博客
前言

今天上了个数据结构课,直接自闭了,记得学习C++已经是去年的事了,再看语法已经忘得七七八八,所以写一篇基础知识博客,助人也助我

本博客适用于有C++基础,正在学C语言数据结构的同学,或者是肯动脑思考的同学。

如果你正在学C++,不出意外也会有所收获,尤其是指针和结构体(华农非计科这部分考的不多)。

关于代码风格,这个因人而异,开始我也喜欢一对中括号对齐,后来写Java慢慢适应左右分开。

最后,因本人能力有限,文章不足之处还望多多指正。

编程模板

C语言模板

#include int main(void) { printf("我爱帅帅龙!");return 0;
}

常用数据类型

简单数据类型:

  • char
  • int
  • long
  • float
  • double

复杂数据类型:

  • 各种数组

查看某种数据类型所占字节数:

#include
#include int main(){printf("int 存储大小 : %d \n", sizeof(int));return 0;
}
//输出int 存储大小 : 4

转义字符

  • \n 换行符,类似按下了回车
  • \t 横向制表符,输出4个空格

输入输出

C语言使用scanf进行输入,使用printf进行输出,当输入简单数据类型的时候要加上&取址符,但是输出不用加&取址符,与Python的格式化相似,请看案例。

输入输出一个整数(简单数据类型):

#include int main(void) {printf("请输入一个整数:");int i;scanf("%d",&i);printf("你输入的整数是%d",i);return 0;
}

输入输出一个字符数组(复杂数据类型):

#include int main(void) {printf("请输入一段字符:");char ch[20];scanf("%s",ch);printf("你输入的一段字符是%s",ch);return 0;
}

OK,那为什么会这样呢?其实可以这样理解:

在输入的时候,计算机需要知道变量的地址,因此需要加上取址符,在输出的时候只需要写变量就好了,如果这时候再加上取址符就会得到地址,在格式化的时候原来的变量就变成相应的地址了,注意,数字数组不能直接输入输出,只有字符数组可以,可以看看下面的例子:

#include int main(void) {printf("请输入一个整数:");int i;scanf("%d",&i);printf("你输入的整数是%d",&i);return 0;
}

除此之外,输入字符还有多种形式,在此不过多介绍

输入输出格式化
格式化方式输入输出含义
%d输入/输出十进制整数,一般对应int类型
%c输入/输出字符,一般对应char类型
%f输入/输出十进制实数,一般对应float类型,也可以是double类型
%s输入字符或字符数组,输出字符数组
%%输出百分号(%)

数组的定义与初始化

常见的数组有字符数组,数值数组,数组支持索引的形式访问和修改元素,在创建的时候需要写上数组大小,通常我们使用数组实现顺序表,时间复杂度为O(1)

数值数组的初始化可以这样来:

double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};

字符数组初始化有两种形式可以选择:

char ch_1[] = "hello";
char ch_2[] = {'h','e','l','l','o','\0'};

除此之外,还有指向数组的指针,我觉得也并不太常用,但是还是介绍一下吧,其实就是通过地址+1的形式,再解引用获取某数据所在地,再赋值或更新

#include int main (){double balance[5] &#61; {1000.0, 2.0, 3.4, 17.0, 50.0};double *p &#61; balance;printf("使用指针的数组值\n");for (int i&#61;0;i<5;i&#43;&#43;){printf("*(p&#43;%d):%f\n",i,*(p&#43;i));}return 0;
}

数组作为函数参数

函数不需要讲&#xff0c;因为现阶段我们一般不会去用。简单提一下数组作为函数参数的情况&#xff0c;函数的参数只需要声明是那种数组&#xff0c;再写个形参名即可&#xff0c;不需要写数组大小&#xff0c;即&#xff1a;

#include void printArray(int array[]) {for (int i&#61;0;i<5;i&#43;&#43;) {printf("%d\n",array[i]);}
}int main(void) {int array[]&#61;{1,2,3,4,5};printArray(array);return 0;
}

结构体的定义与使用

结构体类似简单的类&#xff0c;用struct关键字声明&#xff0c;其中有变量或常量存储数据&#xff0c;如果声明后面加上变量名表示创建了一个实例&#xff0c;名为book&#xff0c;注意&#xff0c;末尾的;不可省略

struct Books{char title[50];char author[50];char subject[100];int book_id;
} book;

结构体也可以直接初始化&#xff0c;如下&#xff1a;

struct Books{char title[50];char author[50];char subject[100];int book_id;
} book &#61; {"C 语言", "RUNOOB", "编程语言", 123456};

指向结构体的指针

如下&#xff0c;LinkList等价于Node*&#xff0c;以后函数返回值或直接声明就可以直接使用LinkList&#xff0c;返回的是一个存放地址信息的指针变量类型

#include
//LinkList为指向Node的结构指针类型&#xff0c;即Node*类型
typedef struct Node {int data;struct Node *next;
}Node,*LinkList;int main (){Node *p;p &#61; (LinkList)malloc(sizeof(Node));p->data &#61; 11;printf("%d",p->data);return 0;
}

何为指针与指针类型变量

我们可以使用取址符&得到变量的地址&#xff0c;其返回值是对应类型的指针类型&#xff0c;例如&#xff1a;

#include int main(void) {int i&#61;1;int *p &#61; &i;printf("当前地址是:%d",p);return 0;
}

字符数组的变量名就表示首地址&#xff0c;所以可以直接输入&#xff1a;

#include int main(void) {char ch[10];scanf("%s",ch);printf("输入的是:%s",ch);return 0;
}

什么叫引用&#xff0c;什么叫解引用&#xff1f;

引用就可以理解为指针类型的数据。例如int *p&#xff0c;此时p就可以成为引用&#xff0c;他的值是地址&#xff0c;*p表示解引用&#xff0c;代表这个地址的对象

#include int main(void) {int i&#61;1;int *p &#61; &i;printf("当前地址是:%d\n",p);printf("数值是:%d\n",*p);return 0;
}

指针类型变量

以BOOK这个结构体为例&#xff0c;其定义如下&#xff1a;

typedef struct Book {int book_id;
} Book;

整体代码如下&#xff1a;

#include typedef struct Book{int book_id;
} Book;int main(void) {Book book1,book2;Book *p &#61; &book2;//结构体类型访问元素使用.book1.book_id &#61; 10;//指针类型的结构体访问元素使用->p->book_id &#61; 10;//输出一下printf("book1的id是%d&#xff0c;book2的id是%d",book1.book_id,p->book_id);return 0;
}

从上面的代码格式可以看出&#xff1a;

  • 指针类型变量是指针类型的数据&#xff0c;存放的是某变量的地址&#xff0c;应当先创建变量&#xff0c;再取值
  • 如果是结构体类型的数据可以直接使用.操作符获取元素或赋值
  • 如果是指针类型数据需要使用->操作符获取元素或赋值

指针对象作为参数的函数

先看下面的代码&#xff0c;发现运行之后book的id没有发生变化&#xff0c;这是因为传参的问题&#xff1a;

#include typedef struct Book{int book_id;
} Book;void add(Book book) {book.book_id &#43;&#61; 1;
}int main(void) {Book book1&#61;{1};printf("book1的原始id是%d\n",book1.book_id);add(book1);printf("book1的现在id是%d\n",book1.book_id);return 0;
}

如果想使用指针将数据进行修改&#xff0c;需要将参数类型修改成指针类型变量&#xff0c;例如&#xff1a;

#include typedef struct Book{int book_id;
} Book;void add(Book *book) {book->book_id &#43;&#61; 1;
}int main(void) {Book book1&#61;{1};printf("book1的原始id是%d\n",book1.book_id);add(&book1);printf("book1的现在id是%d\n",book1.book_id);return 0;
}

数组的变量名就表示首地址

*(p&#43;1)*(balance&#43;1)的效果是一样的&#xff0c;因为p存放的就是数组的首地址&#xff0c;而数组名也表示数组的首地址

#include int main (){double balance[5] &#61; {1000.0, 2.0, 3.4, 17.0, 50.0};double *p &#61; balance;printf("使用指针的数组值\n");for (int i&#61;0;i<5;i&#43;&#43;){printf("*(p&#43;%d):%f\n",i,*(p&#43;i));}printf( "使用balance作为地址的数组值\n");for (int i&#61;0;i<5;i&#43;&#43;){printf("*(balance&#43;%d):%f\n",i,*(balance&#43;i));}return 0;
}

强制类型转换

#include int main(){int sum &#61; 17, count &#61; 5;double mean;mean &#61; (double) sum / count;printf("Value of mean : %f\n", mean );
}

一些排序算法

大家可以看看菜鸟教程实现的六大排序&#xff1a;

https://www.runoob.com/cprogramming/c-sort-algorithm.html

几个可能用到的函数

free——释放内存

把a这个变量给释放掉

int a[10];
free(a);

malloc——申请内存(初始化)

仅仅是申请内存了&#xff0c;类似于C&#43;&#43;的new&#xff0c;但是里面怎么初始化咱不知道&#xff0c;可以后面再进行赋值。Linklist是指针类型变量&#xff0c;如果没有声明&#xff0c;直接写原变量类型的指针变量声明形式&#xff0c;这里是链表的部分代码&#xff0c;可以写成Node*

Linklist L&#61;(Linklist)malloc(sizeof(Node));

几个常见的关键字

#define

#define 是 C 指令&#xff0c;用于为各种数据类型定义别名&#xff0c;与 typedef 类似&#xff0c;但是它们有以下几点不同&#xff1a;

  • typedef 仅限于为类型定义符号名称&#xff0c;#define 不仅可以为类型定义别名&#xff0c;也能为数值定义别名&#xff0c;比如您可以定义 1 为 ONE。
  • typedef 是由编译器执行解释的&#xff0c;#define 语句是由预编译器进行处理的。

#include #define TRUE 1
#define FALSE 0int main( ){printf( "TRUE 的值: %d\n", TRUE);printf( "FALSE 的值: %d\n", FALSE);return 0;
}

typedef

typedef来为类型取一个新的名字&#xff0c;例如给cahr起一个别名叫BYTE&#xff0c;这样&#xff0c;在代码中写char或BYTE都是一个意思了&#xff1a;

typedef char BYTE;

同时&#xff0c;我们还可以为结构体起个别的名字&#xff1a;

typedef struct Books{char title[50];char author[50];char subject[100];int book_id;
} Book;

const

被修饰的变量或数组具有只读特性&#xff0c;不能够被更改&#xff1b;若想对变量重新赋值&#xff0c;则是错误的。

此外&#xff0c;const修饰变量还起到了节约空间的目的&#xff0c;通常编译器并不给普通const只读变量分配空间&#xff0c;而是将它们保存到符号表中&#xff0c;无需读写内存操作&#xff0c;程序执行效率也会提高。

除此之外&#xff0c;const还能修饰函数参数、指针&#xff0c;不再一一介绍

const int i &#61; 5;

sizeof

sizeof 可以获得数据类型或变量在内存中所占的字节数&#xff0c;同时&#xff0c;用 sizeof 也可以获得整个数组在内存中所占的字节数&#xff0c;例如&#xff0c;这个输出40&#xff1a;

# include
int main(void){ int a[10] &#61; {0};printf("sizeof(a) &#61; %d", sizeof(a));return 0;
}

一些问题

变量定义在函数内出错

变量如果定义在函数内&#xff0c;当执行完函数变量会自行销毁&#xff0c;呜呜呜&#xff0c;别乱定义

使用指针类型变量的时候要malloc

使用指针类型数据声明变量的时候&#xff0c;需要使用malloc分配内存&#xff0c;要不然没有空间&#xff0c;如果是非指针类型数据就不用使用malloc了&#xff0c;它声明的时候自动分配空间了


推荐阅读
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了C函数ispunct()的用法及示例代码。ispunct()函数用于检查传递的字符是否是标点符号,如果是标点符号则返回非零值,否则返回零。示例代码演示了如何使用ispunct()函数来判断字符是否为标点符号。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
author-avatar
mobiledu2502909783
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有