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

本文档详细介绍了C语言的基础知识,包括数据类型、输入输出、数组、指针、结构体和基本的内存管理。讨论了指针在数组和结构体中的应用,以及如何通过指针进行数据操作。还提到了一些常用的编程技巧,如格式化输入输出、转义字符和强制类型转换。此外,简要介绍了排序算法和函数参数传递,特别是指针在函数参数中的使用。
摘要由CSDN通过智能技术生成

前言

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

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

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

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

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

编程模板

C语言模板

#include <stdio.h>

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

常用数据类型

简单数据类型:

  • char
  • int
  • long
  • float
  • double

复杂数据类型:

  • 各种数组

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

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

转义字符

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

输入输出

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

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

#include <stdio.h>

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

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

#include <stdio.h>

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

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

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

#include <stdio.h>

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 <stdio.h>

int main (){
   double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
   double *p = balance;

   printf("使用指针的数组值\n");
   for (int i=0;i<5;i++){
       printf("*(p+%d):%f\n",i,*(p+i));
   }
   return 0;
}

数组作为函数参数

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

#include <stdio.h>

void printArray(int array[]) {
    for (int i=0;i<5;i++) {
        printf("%d\n",array[i]);
    }
}

int main(void) {
    int array[]={1,2,3,4,5};
    printArray(array);
	return 0;
}

结构体的定义与使用

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

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

结构体也可以直接初始化,如下:

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

指向结构体的指针

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

#include <stdio.h>
//LinkList为指向Node的结构指针类型,即Node*类型
typedef struct Node {
    int data;
    struct Node *next;
}Node,*LinkList;

int main (){
   Node *p;
   p = (LinkList)malloc(sizeof(Node));
   p->data = 11;
   printf("%d",p->data);
   return 0;
}

何为指针与指针类型变量

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

#include <stdio.h>

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

字符数组的变量名就表示首地址,所以可以直接输入:

#include <stdio.h>

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

什么叫引用,什么叫解引用?

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

#include <stdio.h>

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

指针类型变量

以BOOK这个结构体为例,其定义如下:

typedef struct Book {
   int book_id;
} Book;

整体代码如下:

#include <stdio.h>

typedef struct Book{
   int book_id;
} Book;

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

从上面的代码格式可以看出:

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

指针对象作为参数的函数

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

#include <stdio.h>

typedef struct Book{
   int book_id;
} Book;

void add(Book book) {
    book.book_id += 1;
}

int main(void) {
    Book book1={1};
    printf("book1的原始id是%d\n",book1.book_id);
    add(book1);
    printf("book1的现在id是%d\n",book1.book_id);
	return 0;
}

如果想使用指针将数据进行修改,需要将参数类型修改成指针类型变量,例如:

#include <stdio.h>

typedef struct Book{
   int book_id;
} Book;

void add(Book *book) {
    book->book_id += 1;
}

int main(void) {
    Book book1={1};
    printf("book1的原始id是%d\n",book1.book_id);
    add(&book1);
    printf("book1的现在id是%d\n",book1.book_id);
	return 0;
}

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

*(p+1)*(balance+1)的效果是一样的,因为p存放的就是数组的首地址,而数组名也表示数组的首地址

#include <stdio.h>

int main (){
   double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
   double *p = balance;

   printf("使用指针的数组值\n");
   for (int i=0;i<5;i++){
       printf("*(p+%d):%f\n",i,*(p+i));
   }

   printf( "使用balance作为地址的数组值\n");
   for (int i=0;i<5;i++){
       printf("*(balance+%d):%f\n",i,*(balance+i));
   }
   return 0;
}

强制类型转换

#include <stdio.h>
 
int main(){
   int sum = 17, count = 5;
   double mean;
 
   mean = (double) sum / count;
   printf("Value of mean : %f\n", mean );
}

一些排序算法

大家可以看看菜鸟教程实现的六大排序:

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

几个可能用到的函数

free——释放内存

把a这个变量给释放掉

int a[10];
free(a);

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

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

Linklist L=(Linklist)malloc(sizeof(Node));

几个常见的关键字

#define

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

  • typedef 仅限于为类型定义符号名称,#define 不仅可以为类型定义别名,也能为数值定义别名,比如您可以定义 1 为 ONE。
  • typedef 是由编译器执行解释的,#define 语句是由预编译器进行处理的。
#include <stdio.h>
 
#define TRUE  1
#define FALSE 0
 
int main( ){
   printf( "TRUE 的值: %d\n", TRUE);
   printf( "FALSE 的值: %d\n", FALSE);
 
   return 0;
}

typedef

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

typedef char BYTE;

同时,我们还可以为结构体起个别的名字:

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

const

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

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

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

const int i = 5;

sizeof

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

# include <stdio.h>
int main(void){   
    int a[10] = {0};
    printf("sizeof(a) = %d", sizeof(a));
    return 0;
}

一些问题

变量定义在函数内出错

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

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

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

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

笼中小夜莺

嘿嘿嘿,请用金钱尽情地蹂躏我吧

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

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

打赏作者

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

抵扣说明:

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

余额充值