数据结构中的C语言编程基础

​ 在学习数据结构时,需要我们编写许多的程序,对于一些变量的定义、结构体的声明、指针的使用,需要有一个统一的标准,这样才能方便我们使用、并简化记忆难度。

​ 本文结合自身的编程经验和高分笔记中对考研数据结构编程的一些建议,整理出这么一篇C语言编程入门基础,主要面向数据结构中数据类型的定义,希望能对你有所帮助。

1.Hello World示例

#include <stdio.h>
 
int main()
{
   /* 我的第一个 C 程序 */
   printf("Hello, World! \n");
   
   return 0;
}

​ 上面就是编程语言学习的’创世之光’–Hello World!,只要他执行成功了,那么我们就算是一只脚踏进了圈子。

资源分配图

​ 一个基础的C程序,主要包含五个部分:预处理器指令(include加载的头文件)、函数、变量、语句&表达式、注释。

2.C基础语法

​ C语言的基础语法,不在本文赘述,可以参考下面文章进行学习或复习。

C语言教程

3.输入与输出

​ 当我们提到输入时,这意味着要向程序填充一些数据。输入可以是以文件的形式或从命令行中进行。C 语言提供了一系列内置的函数来读取给定的输入,并根据需要填充到程序中。

​ 当我们提到输出时,这意味着要在屏幕上、打印机上或任意文件中显示一些数据。C 语言提供了一系列内置的函数来输出数据到计算机屏幕上和保存数据到文本文件或二进制文件中。

​ 当然,我们在基本的编程练习时,不需要涉及到文件的操作,只需要通过键盘、屏幕进行数据的输入与输出。在本文中,我们主要讲下scanf() 和 printf() 函数。

3.1输入

​ scanf函数的声明如下:

int scanf(const char *format, ...);

​ 使用C的输入输出函数,有一点比较让初学者头疼,就是较为繁多的%s、%d等等。不过了解了之后,还是很方便使用的。

资源分配图
#include <stdio.h>

int main(void)
{
    int a,b,c;
    printf("请输入三个数字:");
    scanf("%d%d%d",&a,&b,&c);
    printf("%d,%d,%d\n",a,b,c);
    printf("请再输入三个数字:");
    scanf("%d, %d, %d",&a,&b,&c);
    printf("%d,%d,%d\n",a,b,c);
    return 0;
}

​ 执行结果如下图所示,一定要注意,scanf中的format不要有过多的修饰,比如:scanf(“please input three numbers:%d%d%d”,&a,&b,&c),因为format决定了你输入数据时的结构。如scanf("%d%d%d",&a,&b,&c),几个输入之间可以使用空格分隔,而scanf("%d, %d, %d",&a,&b,&c),必须使用’,‘分隔,且’,'前不能有空格。

资源分配图

3.2输出

​ 输出的函数printf的声明如下:

int printf(const char *format, ...);

​ 其中的参数format是字符串,包含了要被写入到标准输出 stdout 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length]specifier,具体讲解如下:

资源分配图

​ 其余更细致的文档说明,可以参考这篇文档

#include <stdio.h>
int main()
{
   char ch = 'A';
   char str[20] = "lizishudd.blog.csdn.net";
   float flt = 10.234;
   int no = 150;
   double dbl = 20.123456;
   printf("字符为 %c \n", ch);
   printf("字符串为 %s \n" , str);
   printf("浮点数为 %f \n", flt);
   printf("整数为 %d\n" , no);
   printf("双精度值为 %lf \n", dbl);
   printf("八进制值为 %o \n", no);
   printf("十六进制值为 %x \n", no);
   return 0;
}

​ 执行结果如下图所示:

资源分配图

4.数组

4.1一维数组

​ 数组由多个相同数据类型的变量组合起来的,数组的声明方式如下,其中type为变量类型。

#define arraySize = 5
//arraySize为已经定义的常量
type arrayName [ arraySize ];
//for example
int a[5];

​ 数组的初始化,可以通过定义时初始化或通过键盘输入初始化。主要代码如下:

#include <stdio.h>
#define arraySize 5

int main(int argc, const char * argv[]) {
    //arraySize为已经定义的常量
    int a[arraySize];
    //定义时初始化
    //如果b[]中不限制长度,则数组的长度由{}中的元素个数觉得
    int b[5] = {1, 3, 5, 7, 9};
    printf("请输入数组中的值:");
    for(int i = 0; i<arraySize; i++){
        scanf("%d", &a[i]);
    }
    printf("数组A中的值:");
  	//通过输入初始化数组
    for(int i = 0; i<arraySize; i++){
        printf("%d ", a[i]);
    }
    printf("\n");
    printf("数组B中的值:");
    for(int i = 0; i<sizeof(b)/sizeof(int); i++){
        printf("%d ", b[i]);
    }
    printf("\n");
    return 0;
}

​ 执行结果如下:

资源分配图

4.2二维数组

​ C 语言支持多维数组。多维数组声明的一般形式如下:

type name[size1][size2]...[sizeN];
//for example
int threeDim[5][10][4];

​ 一般我们只会用到二维数组,更高维度的数组理论上都是相同的。一个二维数组可以认为是带有x行、y列的表格,如int x[3][4],他是一个包含三行、四列的二维数组。

资源分配图

二维数组的初始化和一维数组类似,可参考下面代码:

int a[3][4] = {  
 {0, 1, 2, 3} ,   /*  初始化索引号为 0 的行 */
 {4, 5, 6, 7} ,   /*  初始化索引号为 1 的行 */
 {8, 9, 10, 11}   /*  初始化索引号为 2 的行 */
};
//内部嵌套的括号是可选的,下面的初始化与上面是等同的:
int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
//也可以通过键盘输入来初始化
for(i = 0; i < 3; i++){
  printf("请输入%d行的数据:", i+1);
  for(j = 0; j < 4; j++){
    scanf("%d", &a[i][j]);
  }
  printf("\n");
}

​ 当数组作为函数的参数是,函数的定义应当如何写?

//void 参数都是可调的
//一维数组作为参数的函数定义方法如下
void f(int x[], int n){
  //insert code here ...
}
//二维数组作为参数的函数定义方法如下
//不需要传入行数,必须传入列数,且传入的数组的第二维度的长度必须是maxSize
void f(int x[][maxSize], int n){
  //insert code here ...
}

5.指针

​ 指针一直是让人恐惧的知识点,但是在数据结构中,指针是你无法逃避的。不过指针的学习既简单又有趣,需要我们去正确的面对。通过指针,可以简化一些编程任务的执行。还有一些任务,如动态内存分配,没有指针是无法执行的。

​ 对于其他类型的变量,变量里装的是数据元素的内容,而指针变量里装的是变量的地址,通过它可以找出这个变量在内存中的位置,就像一个指示方向的指针,指出某个变量的位置。

​ 对于每种变量,指针的定义方法都有相似的规则,如以下语句:

//int型变量的定义语句,int a
int *a;
char *b;
float *a;
//结构体,参考第6节的内容
TypeA *d;

​ 与其他变量的定义相对比,指针型变量的定义只是在变量名之前多一个’*’。对于指针地址、变量的解释,可以参考下图:

资源分配图

​ 指针使用的案例如下所示,更详细的用法还需要读者自行探索。

#include <stdio.h>

int main(int argc, const char * argv[]) {
    int  var = 20;   /* 实际变量的声明 */
    /*
     指针变量的声明
     如果无明确的指向,赋值为NULL
     */
    int  *ip = NULL;
    /* 在指针变量中存储 var 的地址 */
    ip = &var;
    printf("var 变量的地址: %p\n", &var);
    /* 在指针变量中存储的地址 */
    printf("ip 变量存储的地址: %p\n", ip);
    /* 使用指针访问值 */
    printf("*ip 变量的值: %d\n", *ip);
    return 0;
}

6.结构体

​ 了解结构体前,需要知道typedeftypedef可以理解为给现有的数据类型起一个新名字,如:

typedef struct {...} TypeA

​ 新定义的结构体没有名字,因此用typedef给他起个名字是有必要的。

结构体就是系统提供给程序员制作新的数据类型的一种机制,即可以用系统已有数据类型(int,char,float…)或用户定义的结构型为原料,组合成用户需要的复杂数据类型。(可以理解成面向对象编程中的类)

​ 一般而言,可以在创建结构体时定义变量,但是为了书写统一,我们先通过typedef定义新类型,在创建新的变量。

//用typedef创建新类型
typedef struct
{
    int a;
    char b;
    double c; 
} TypeA;
//现在可以用TypeA作为类型声明新的结构体变量
TypeA a, a1[20], *a2;

​ 可以看到,结构体定义后,可以和int、char等基本数据类型一样使用,用于定义数组、指针等。当需要访问数组中的数据时,可以通过a1[index].a来访问。示例如下所示:

#include <stdio.h>

typedef struct
{
    int a;
    char b;
    double c;
} TypeA;

int main() {
    //现在可以用TypeA作为类型声明新的结构体变量
    TypeA a = {1, 'a', 12};
    printf("a中的值为:%d,%c,%f\n", a.a, a.b, a.c);
    TypeA *a2 = &a;
  	//需注意,a2->a或(*a2).b
    printf("a2中的值为:%d,%c,%f\n", a2->a, (*a2).b, a2->c);
    TypeA a3[2];
    a3[0] = a;
    a3[1] = a;
    printf("a3[0]中的值为:%d,%c,%f\n", a3[0].a, a3[0].b, a3[0].c);
    printf("a3[1]中的值为:%d,%c,%f\n", a3[1].a, a3[1].b, a3[1].c);
    return 0;
}

​ 在数据结构中,结构体更常见的应用,是和指针结合起来构造结点(链表的结点、二叉树的结点等)。下面我们来一起看下常用结点的"构造"。

6.1链表结点

​ 链表结点有两个域:一个是数据域,用于存放数据;另一个是指针域(指针域可以有多个,如双向链表结点),用于存放下一个结点的位置,链表结点的结构型定义如下:

typedef struct Node{
  //这里默认是int型,如其他类型可以修改
  int a;
  //指向Node型变量的指针
  struct Node *next;
}Node;

注意:凡是结构型内部含有指向和自己相同类型的指针,即Node结点中有指向Node结点的指针变量,则在定义Node的语句后,需要加上Node这个结构型的名字,如typedef struct Node。读者可以自己对比下上面定义和上一小节中TypeA定义的区别。

6.2二叉树结点

​ 二叉树结点的构造,也是由链表结点引申出来的,其余类型的结点也都可以类似的进行扩展。二叉树结点的结构型如下:

typedef struct BTNode{
  //这里默认是int型,如其他类型可以修改
  int data;
  //指向左孩子结点的指针
  struct Node *lchild;
  //指向右孩子结点的指针
  struct Node *rchild;
}BTNode;

6.3创建新结点

​ 通过上面讲解,我们也基本知道了结构型结点的定义方法,定义方法还有其他的不同写法,不过我们不用关心太多,以增加记忆负担和理解难度。结构型定义好后,就要用它来制作新结点了。

​ 以二叉树结点为例,创建结点有以下两种写法:

//1
BTNode aNode;
//2
BTNode *bNode;
bNode = (BTBode *) malloc(sizeof(BTNode));

​ 其中,1理解起来比较容易;对于2,分为了两步,首先定义一个结点的指针bNode,然后通过malloc()来申请一个节点的内存空间,最后让指针bNode指向这片内存空间。

​ 其中malloc()函数很重要,需要掌握,以后所有的内存分配基本都可使用malloc()来完成。malloc()的函数声明如下:

void *malloc(size_t size)

​ 通过malloc()申请空间的通用公式如下,其中①、②处填写你所定义的结构型名称,p为指针、指向新创建的结点,sizeof()函数用于测算所需要申请的空间大小。

p = (*)malloc(sizeof()) 

​ 我们还可以通过malloc()来动态的申请数组空间,相对于上面的申请方法,可以认为动态申请了一组空间,语法如下,可以通过p[1]来取第二个元素。

int *p;
p = (int *) malloc(n * sizeof(int));

​ 使用示例如下:

#include <stdlib.h>

    //可以将代码放入第六节中的测试代码中
    //...
		TypeA *node;
    node = (TypeA *)malloc(sizeof(TypeA));
    node->a = 2;
    node->b = 'A';
    node->c = 13;
    printf("node中的值为:%d,%c,%f\n", node->a, node->b, (*node).c);
		//return 0;

参考资料:

1.菜鸟教程–C 语言教程

2.数据结构高分笔记


​ 又到了分隔线以下,本文到此就结束了,本文内容全部都是由博主根据自身理解与对考研资料进行的整理,仅作为参考,大佬有什么问题,可以评论区留言,如果有什么错误,还请批评指正。

​ 本专栏为数据结构知识,喜欢的话可以持续关注,如果本文对你有所帮助,还请还请点赞、评论加关注

​ 有任何疑问,可以评论区留言。

  • 30
    点赞
  • 130
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李子树_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值