初入前端的北京某211大一非科班生(没错上学期还是日语生)的C语言自学笔记
本文约8k字,将介绍:编程基础 数据类型 表达式 语句与控制流 函数 数组,指针 结构体等会随着学习进度推进持续更新~

学习C语言的动机:大一上学期学完 html5 css3 javascript 后,程序对我要求掌握一定的数据结构与算法,而数据结构教材完全是以C语言讲解的,恰好本学期专业课有开展C程序设计语言,顺水推舟地就产生了这篇文章了。当然,绝大部分内容是基于我在csdn上阅读前人的经验所学习的,因此本文档可能更是一篇学习总结。

感谢你的阅读,让我们开始C程序设计语言入门的学习


编程

让计算机为解决某个问题 而使用某种 程序设计语言编写程序代码 并最终得到结果 的过程

计算机程序

计算机所执行的一系列的 指令集合

计算机语言

机器语言、汇编语言、高级语言

机器语言: 计算机最终执行的语言 由0和1组成的二进制数 二进制是计算机语言的基础
编程语言: 控制计算机的指令 有固定格式和词汇
分为汇编语言和编程语言

汇编语言: 和机器语言实质相同 都是直接对硬件操作 指令采用英文缩写的标识符

高级语言: C C++ Java C# Python PHP JavaScript Go语言 Objective-C Swift

编程语言和标记语言(html)区别

编程语言 很强的逻辑性和行为能力 诸如if else, for, while等具有逻辑性和行为能力的指令 主动

标记语言(html) 不用于向计算机发出指令 常用于格式化和链接 标记语言的存在是用来被读取 被动

翻译器

高级语言所编制的程序不能直接被计算机识别 必须经过转换才能被执行
翻译器:源代码——>机器语言 这一步也被称为 二进制化

数据类型

数据类型规定如何解读数据

  • int 整型 字节4 -215 ~ 215-1

  • char 字符型 字节1

  • short 短整型 字节2 -215 ~ 215-1

  • long 长整型 字节8 -231 ~ 231-1

  • unsigned int 无符号整型 字节4 0 ~ 216-1

  • float 单精度型 字节4 -3.4x10-38 ~ 3.4x1038

  • double 双精度型 字节8 -1.7x10-308 ~ 1.7x10308

  • long double 长双精度型 字节16 -1.2x10-4932 ~ 1.2x104932

  • void* 空类型 字节8

​ // c语言中不存在字符串变量 字符串只能存在于数组中

表达式

表达式是由**操作数(操作对象)运算符(操作符)**组成的式子,表达式是指具有完整意义的计算机指令

表达式的分类:一元 二元 三元

基础运算

四则运算

比较运算(关系运算)

< > <= >= == !=

float\double 无法精确判等 存在精度问题

c语言中没有布尔型 真:非0 假:0

位(bit)运算

<< >> 位移运算(快于四则运算) 溢出则丢弃 左移后空缺补0

位运算不支持float\double

逻辑运算(&& || !)按位运算(& | !) 不一样 逻辑运算有真假(非0和0)

  • 按位与(&): 十进制转换为二进制,上下比较,有0则0,两个都是1才1

  • 按位或(~): 上下比较有1则1,两个都是0才0

  • 按位异或(^): 上下比较,相同为0,不同为1

  • 按位左移(<<): 二进制向左移一位,溢出丢弃,右边补零

  • 按位右移(>>): 二进制向右移一位,右边丢弃,左边补原符号位

赋值表达式 += -= *= &= %=

三元表达式 a?b:c if a the b else c

部分单目操作符

&: 每次使用scanf函数时,总要在变量名前加上&,&变量a的意思是取变量a的地址,这是&的作用之一

~ : 对一个数的二进制按位取反

*: 间接访问操作符(解引用操作符)

(类型): 强制类型转换

格式化输出语句 (占位输出)

​ 将各种类型的数据按照格式化后的类型及指定位置从计算机上显示

printf("输出格式符", 输出项);`// %d 带符号十进制整数
int a = 10;
printf("%d", a);
// %c 单个字符
char x = 'a';
printf("%c", x);
// %s 字符串
printf("%s", "string");
// %f 6位小数
float a = 1.23;
printf("%f", a);

格式符的个数要与变量、常量或者表达式个数一一对应

int a = 10;
float b = 7.56;
char x = 'c';
printf("%d, %f, %c", a, b, x);

类型:

d 有符号10进制整型

i 有符号10进制整型

u 无符号10进制整型

o 无符号8进制整型

x 无符号8进制整型

X 无符号16进制整型

f 单、双精度浮点数(默认保留6位小数)

e/E 以指数形式输出单、双精度浮点数

g/G 以最短输出宽度,输出单、双精度浮点数

c 字符

s 字符串

p 地址

标志和精度:

- 左对齐(默认是右对齐)

+ 当输出值为正数时,在输出值前面加一个 + (默认不显示)

0 右对齐时,用0填充宽度(默认用空格填充)

空格 输出值为正数时,在输出值前面加上空格,为负数时加负号

# 对c/s/d/u类型无影响 对o类型在输出时加前缀o,对x类型输出时加前缀0x

printf("%.2f", a); 保留2位小数

printf("%.*f", n, a); 动态指定保留小数位数n

int a = 1;
int b = 10;
printf("a = |%5d|\n", a);    //  |    1|
printf("a = |%-5d|\n", a);   //  |1    |
printf("a = |%+d|\n", a);    //  |+1|
printf("a = |%05d|\n", a);   //  |00001|
printf("a = |% d|\n", a);    //  | 1|
printf("b = %#x\n", b);      //  0xadouble c = 3.1415;
printf("c = %.2f\n", c);     //  3.14
printf("c = %.*f\n", 3, c);  //  3.142
Scanf函数

scanf函数用于接收键入的内容,是阻塞式函数(程序会停在scanf出现的地方,知道接收到数据才会执行后面的代码)

scanf运行原理:系统会将用户输入的内容先放入输入缓冲区,scanf方式会从输入缓冲区中逐个取出内容赋值给变量,如果输入缓冲区内容不为空,scanf会一直从缓冲区中获取,而不要求再次输入

//  scanf("格式控制字符串", 地址列表);
int number;
scanf("%d", &number);  // 接收一个整数
printf("number = %d\n", number);  // 键入2就输出2,不键入输出0int str;
scanf("%c", &str);  // 接收一个字符
printf("str = %c\n", str);int num2, str2;
scanf("%d,%c", &num2, &str2); // 键入 44,d
printf("%d,%c", num2, str2);  // 打印 44,d
  • 接收非字符和字符串类型时,空格、tab、回车会被忽略
  • \n是scanf函数的结束符号,所以scanf函数中格式化字符串中不能出现\n
不可改变常量

常量: 在程序执行过程中,值不发生改变的量

c语言的常量分为 直接常量和符号常量

  1. 直接常量(字面量): 可以直接拿来使用无需说明的量
  • 整型常量: 13、0
  • 实型常量: 13.33
  • 字符常量: ‘a’
  • 字符串常量: “Hello World!”
  1. **符号常量: 用一个标识符来表示一个常量。符号常量使用前必须先定义。**且不可被改变

    由于预先对标识符进行了定义,在程序的预处理阶段, 编译器会将所有定义的标识符替换成相应的内容并生成 .i 文件

//  #define 标识符 常量值
//  #define N 100
//  编译器在预处理程序时,会将程序中所有的N用100来替换。换言之,不同于const常量,define本质上是对文本内容的替换// #define MAX 100         // 将 MAX 这个标识符和 100 这个数字关联起来
// #define REG register     // 为 register 这个关键字,创建一个简短的名字REG
// #define STR "test_string"  // 用 STR 这样一个名字来代替 test_string 这样一个字符串#include <stdio.h>
#define PI 3.14
#define S(r) PI*r*r  // 定义在主函数前 不要加分号
int main(void)
{printf("area = %f", S(1+2));  // 3.14*1 + 2*1 + 2 = 7.14 直接把r替换成1+2不用加括号// 这实际上,宏就是替换,并且是相当直接的替换return 0;
}

​ #define定义标识 符的本质就是替换

​ define 定义表达式时要注意**“边缘效应”**

#define N 1+2
float a = N/2.0;
/*
按照常规做法,可能会认为结果是3/2 = 1.5
但是实际上,结果应该为 1+2/2.0 = 2.0若想要实现3/2,则#define N (1+2)
即为避免边缘效应,一定要加!括!号!
*/

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏 (define macro)

#define 定义宏可分为两种

  1. 一种是不带参数的宏定义,这也就是第1小节提到的使用#define定义标识符
  2. 第二种是带参数的宏定义,其定义格式如下
//  #定义  宏名(参数表)  内容
#define name( parament-list ) stuff

其中,parament-list是一个由逗号隔开的符号表,它们可能出现在stuff中

#define ADD(a, b) (a + b) // 宏的参数有两个a和b 这个宏所要实现的功能是将a和b相加

宏的使用和C语言中的函数类似,都需要进行传参。在main函数中两者的实现方式几乎是一样的,但具体的实现方式却很不一样

int ADD(int x, int y)
{return x + y;
}
// #define ADD(a, b) a + bint main()
{// ...
}

宏定义的程序中,预处理器会将ADD(a, b)替换成(a + b)。宏定义是将a+b这样一个求和操作重新命名并置于main函数中,而ADD函数是通过函数调用来实现求和,使用了新的函数栈帧

#define替换规则:

  1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换
  2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被它们的值所替换
  3. 最后再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号,如果是,就重复上述过程

注意:

  • 参数列表的左括号必须与name紧邻。如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分
  • 宏参数和#define定义中 可以出现其他#define定义的符号
  • 对于宏,不能出现递归
  • 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索

宏和函数的对比

  • 宏名全部大写,函数名不要全部大写
  • 宏比函数在程序的规模和速度方面更甚一筹
  • 函数的参数必须声明为特定的类型,所以函数只能在类型合适的表达式上使用。宏是类型无关的,不够严谨
  • 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度
  • 宏无法调试
自动类型转换

自动转换发生在不同数据类型运算时,在编译的时候自动完成

char转换为int遵循ASCII码中的对应值

  • 字节小的可以向字节大的自动转换,但字节大的不能向字节小的自动转换
  • char -> int int -> double char -> double
强制类型转换

​ 通过定义类型转换运算来实现 一般形式为:

// (数据类型) (表达式)

其作用是把表达式的运算结果强制转换成类型说明符所表示的类型

注意:

  • 数据类型和表达式都必须加括号。如把(int)(x/2+y)写成(int)x/2+y则成了把x转换成int型之后再除2再与y相加了
  • 转换后不会改变原数据的类型及变量值,只在本次运算中临时性转换
  • 强制转换后的运算结果不遵循四舍五入的原则
运算符号

c语言中的运算符: 算术、赋值、关系、逻辑、三目运算符

算术运算符:+ - * / % ++ - -

注意:

  • 除法中 两个数有一个为小数则结果为小数 如 9.0/2 = 4.500000
  • 取余中 运算后的符号取决于被模数的符号 如(-10)%3 = -1,10%(-3) = 1

关系运算符: > >= == !=

逻辑运算符: &&逻辑与 ||逻辑或 !逻辑非

逻辑运算的值也是有两种分别为真和假,C语言中用整型的1和0来表示

循环结构之for循环
for(表达式1; 表达式2; 表达式3)
{// 执行代码块
}

注意:

  • 表达式123均可不写为空 但分号不能省
  • 省略表达式2(循环条件) 或 表达式3(循环变量增减量) 死循环
如何获得一个数的百位十位个位
  • 百位数: num/100 因为int整数型 765/100=7
  • 十位数: num%100/10 765%100 = 65 65/10 = 6
  • 个位数: num%10 765%10 = 5
break与continue
  • 在没有循环结构的情况下,break不能用在单独的ifelse语句中
  • 在多层循环中,一个break只跳出当前循环
switch
switch(表达式){case 常量表达式1: 执行代码块1 break;……case 常量表达式n: 执行代码块n break;default:  执行代码块n+1;break;
}
  • switch后面的表达式语句只能是整型或字符类型
  • case后面允许有多个语句,可以不用{}括起来
  • 各case和default子句的先后顺序可以变动,不会影响程序执行结果
  • default子句可以省略不用

函数

定义: 函数是子程序,子程序是一个大型程序中的某部分代码,它相较于其他代码具备相对的独立性。一般会由输入参数并由返回值,提供对过程的封装和细节的隐藏

C语言提供了大量库函数,比如stdio.h提供输出函数

自定义函数的一般形式:

[数据类型说明] 函数名称 ([参数])
{执行代码块;return (表达式);
}int main(){...}
  • [] 包含的内容(数据类型说明)可以省略 省略了默认是int类型函数
  • 参数省略表示该函数是无参函数,参数不省略表示该函数是有参函数
  • 自定义函数尽量放在main函数前。如果要放在main函数后面的话,需要在main函数之前先声明自定义函数,声明格式为[数据类型说明] 函数名称 ([参数])
函数调用
函数名 ([参数]);
  • 对无参函数的调用可省略[ ]中的内容
  • []中可以是常数,变量或其他构造类型数据及表达式,多个参数之间用逗号分隔
有参与无参
// 无参函数
[数据类型说明] 函数名称 ()
{// ...return 表达式;
}// 有参函数
[数据类型说明] 函数名称 (参数列表)  // 有参无参唯一区别在于()中多了 参数列表
{// ... return 表达式;
}

有参函数相对灵活,输出内容可以随着n的变化随意变动,只要在main函数中传递一个参数就可以了。而无参函数中输出的相对固定,当需要改动的时候还需要到自定义方法内改变循环变量的值

形参和实参

形参:目的是用来接收调用该函数时传入的参数。只有在被调用时才分配内存单元,在调用结束时即刻释放所分配的内存单元。因此,形参只有在函数内部有效

实参:调用时传递该函数的参数。实参可以是常量、变量、表达式、函数等。应预先用赋值等办法使实参获得确定值。

在参数传递,实参和形参在数量上、类型上、顺序上应严格一致,否则会发生类型不匹配的错误

#include <stdio.h>
int Function(int x) {  // x是形参return x*2;
}
int main() {int x = 10;  // 定义变量x// 下面的x是实参 它其实是main函数中定义的变量printf("x=%d\n", Function(x));return 0;
}
函数的返回值

返回值:函数被调用后,执行函数体中的程序段所取得的 并返回给主调函数的值

  • 函数的值只能通过return语句返回主调函数
  • 函数值的类型和函数定义中函数的类型应保持一致,若不一致则以函数返回类型为准
  • 没有返回值的函数,返回类型为void
  • void函数中可以有执行代码块,但不能有返回值。void函数中如果有return语句,该语句只能起到结束函数运行的功能,其格式为return;
递归函数

​ 递归就是一个函数在它的函数体内调用自身。执行递归函数将反复调用其自身,每调用一次就进入新的一层。递归函数必须有结束条件

递归函数特点:

  • 每一级函数调用时都有自己的变量,但是函数代码并不会得到复制。如计算5的阶乘时每递推一次变量都不同
  • 每次调用时都会有一次返回,如计算5的阶乘时每递推一次都返回进行下一次
  • 递归函数中,位于递归调用前的语句和各级被调用函数具有相同的执行顺序
  • 递归函数中,位于递归调用后的语句的执行顺序和各个被调用函数的顺序相反
  • 递归函数中必须有终止语句

因此,递归函数是 自我调用且有完成状态

// 递归demo  有5个人坐在一起,问第5个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第3个人,又说比第2人大两岁。问第2个人,说比第1个人大两岁。最后 问第1个人,他说是10岁。请问第5个人多大?
// 程序分析:利用递归的方法,递归分为回推和递推两个阶段。要想知道第5个人岁数,需知道第4人的岁数,依次类推,推到第1人(10岁),再往回推。#include <stdio.h>
int dfs(int n) {return n == 1 ? 10 : dfs(n - 1) + 2;
}
int main()
{ printf("第5个人的年龄是%d岁", dfs(5)); return 0;
} 
局部与全局

变量按作用域范围可分为局部变量和全局变量

  • 局部变量(内部变量)作用域仅限于函数内,离开该函数后再使用这种变量是非法的
  • 全局变量(外部变量)定义在函数外部的变量,它不属于任何函数,它属于一个源程序文件,其作用域是整个源程序

在所有函数之外声明的函数叫做全局变量

变量存储类别

C语言根据变量的生存周期来划分,可以分为静态存储方式和动态存储方式

  • 静态存储方式:在程序运行期间分配固定的存储空间。静态存储区中存放了在整个程序执行过程中都存在的变量,如全局变量。静态存储是只读的,存放的是指令
  • 动态存储方式:在程序运行期间根据需要进行动态分配存储空间。动态存储区中存放的变量是根据程序运行的需要而建立和释放的,通常包括:函数形式参数、自动变量、函数调用时的现场保护和返回地址等

C语言中存储类别又分为四类:

  • 自动(auto)
  • 静态(static)
  • 寄存器的(register)
  • 外部的(extern)
  1. 用关键字auto定义的变量为自动变量,auto可省略,auto不写则隐含定为“自动存储类别",属于动态存储方式

int fn(int a) {   // 定义fn函数, a为参数auto int b, c;  // 定义b,c为 自动变量
}
  1. 用static修饰的为静态变量,如果定义在函数内部称为静态局部变量,定义在函数外部称为静态外部变量

    #include <stdio.h>
    void fn()
    {static int i = 0;   // static修饰局部变量i++;printf("%d\n", i);
    }
    int main()
    {int i;for(i=0; i<10; i++){fn();}return 0;
    }
    // 输出: 1 2 3 ... 10
    // 函数内的局部变量并没有每次调用都是为变量i开辟内存空间,而是将变量i的值保存了下来
    

    由此可见:static修饰局部变量改变了变量的生命周期,让静态局部变量超出了作用域后依然存在,直到程序结束时,生命周期才结束

    注意:静态局部变量属于静态存储类别,在静态存储区内分配存储单元在程序整个运行期间都不释放;静态局部变量在编译时赋初值,即只赋初值一次;如果在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符变量)

    另外,static修饰全局变量和修饰函数的时候,这个全局变量/函数只能在本源文件中使用,不能在其他源文件内使用

  2. 为了提高效率,C语言允许将局部变量的值存放在CPU的寄存器内,这种变量叫做“寄存器变量(register)”

    void fn() {register int i;  // 定义i为寄存器类型变量
    }
    

    只有局部自动变量和形式参数可以作为寄存器变量;不能定义任意多个寄存器变量;局部静态变量不能定义为寄存器变量

  3. 外部变量用extern声明,外部变量的意义是某函数可以调用在该函数之后定义的变量

    #include <stdio.h>
    int main()
    {extern int x;  // 这里声明使用的是外部全局变量printf("extern x=%d\n", x);return 0;
    }
    int x = 100;
    
内部函数与外部函数
  • 在C语言中不能被其他源文件调用的函数称为内部函数,内部函数由static关键字定义,又被称为静态函数,static[数据类型]函数名([参数])
  • static是对函数的作用范围的一个限定,限定该函数只能在其所处的源文件中使用,因此在不同文件中出现相同的函数名称的内部函数是没有问题的
  • 在C语言中能被其他源文件调用的函数称为外部函数,外部函数由extern定义,形式同上
  • 在没有指定函数的作用范围时,系统默认是外部函数,因此当需要定义外部函数时extern也可以省略
// 外部函数demo
// main.c
#include <stdio.h>
void main() {extern void test();  // 调用在其他函数中定义的三个函数...
}// test.c
#include <stdio.h>
void test() {// 定义外部函数test
}

数组

数组初始化

数组在程序中是一块连续的,大小固定并且里面的数据类型一致的内存空间数组初始化的语法:

int arr[3] = {1, 2, 3};
int arr2[] = {1, 2, 3};
// 获取数组元素:arr[0];
  • 数组初始化时,数组内元素个数 <= 声明的数组长度,并且多余的数组元素初始化为0
  • 在声明数组后没有进行初始化的时候,静态(static)和外部(extern)类型的数组元素初始化元素为0,自动(auto)类型的数组的元素初始化值不确定
数组的遍历
int arr(3) = {1, 2, 3};
int i;
for (i=0; i<=2; i++)
{printf("%d\n", arr[i]);
}
return 0;
  • 循环变量不要超出数组的长度
  • C语言的数组长度一经声明就是固定,无法改变
  • C语言不提供计算数组长度的方法
// 获取数组长度
int length = sizeof(arr)/sizeof(arr[0]);
数组作为函数参数

数组可以由整个数组当作函数的参数,也可以由数组中的某个元素当作函数的参数

// 整个数组当作函数参数 即**把数组名称传入函数**中
#include <stdio.h>
void temp(int arr[]) {   // 函数没有返回值或函数无参数 声明为void hint i;for (i=0; i<=4; i++) {printf("%d\n", arr[i]);}
}
int main() {int arr[5] = {1, 2, 3, 4, 5};temp(arr);  // 传数组return 0;
}
// 数组中的元素当作函数参数,即把数组中参数传入函数中
#include <stdio.h>
void temp(int arrValue) {printf("%d\n", arrValue);
}
int main() {int arr[5] = {1, 2, 3, 4, 5};temp(arr[3]);  // 传数组中的参数return 0;
}
  • 数组名作为函数实参传递时,函数定义处 作为接收参数的数组类型形参 既可以指定长度也可以不指定长度
  • 数组元素作为函数实参传递时,数组元素类型必须与形参数据类型一致

例1:冒泡排序

// 冒泡排序
#include<stdio.h>void Function(int arr[]) {int i, j, length;length = sizeof(arr);printf("arr's length is %d", length);printf("\nbefore: ");for(i=0; i<length; i++) {if(i != length-1) {printf("%d, ", arr[i]);} else {printf("%d", arr[i]);}}for(i=0; i<length-1; i++) {for(j=0; j<=i; j++) {if(arr[j]<arr[j+1]) {int temp;temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}printf("\nafter: ");for(i=0; i<length; i++) {if(i != length-1) {printf("%d, ", arr[i]);} else {printf("%d", arr[i]);}}
}int main()
{int arrTest[] = {0, 5, 6, 2, 9, 4, 3, 1};Function(arrTest);return 0;
}

例2:数组查找

#include <stdio.h>
int getIndex(int arr[5], int value) {  // value是要查询的元素int i, index;  // index将是查询元素的下标 元素不存在则赋值-1for(i=0; i<5; i++) {if(arr[i]==value) {  // 某个元素==查询的元素index = i;  // 获得查询元素的下标break;}index = -1;}return index;
}int main() {int arr[5]={3,14,64,2,8};  // 实参1int value = 8;  // 实参2int index = getIndex(arr, value);  //  调用函数并传参:声明返回值=函数(实参)if(index!=-1) printf("%d存在, 下标为%d\n", value, index);elseprintf("%d不存在\n", value);return 0;
}
字符串与数组

C语言中无法直接定义字符串数据类型,但是我们可以使用数组定义我们想要的字符串

// 定义
char stringName[length] = "字符串值";
char stringName[length] = {'字符1', '字符2', '字符n', '\0'};
// 输出
printf("%s", stringName);
puts(stringName);
  • []中的length可以省略
  • 采用第二种方式时最后一个元素必须是’\0’,'\0’表示字符串的结束标志
  • 采用第二种方式时数组种不能写中文
字符常量和字符串常量

C语言中用单引号表示字符常量,双引号表示字符串常量

字符常量: 用一对单引号括起来的一个字符,如’a’, ‘9’, ‘!’ ,字符常量中的单引号只起定界作用,并不表示字符本身。一个字符常量是一个整数

字符串常量: 字符串常量是用双引号括起来的多个字符的序列,字符串本质上是多个字符组成的字符数组。在每个字符串常量的结尾,系统都会自动加一个字符’\0’作为该字符串的结束标识符,系统据此判断字符串是否结束

字符串函数
  1. strlen(s) 获取字符串长度
// 注意: 字符串中 汉字和字母的长度不一样
char str1[] = "栖夜";
char str2[] = {'i', 'j', 'k', '\0'};
printf("两者长度分别为%d\t%d\n", strlen(str1), strlen(str2));  // 6  3
  1. strcmp(s1, s2) 把字符串转换成ASCII码后比较

    返回值0 表示s1和s2的ASCII码相等

    返回值1 表示s1比s2的ASCII码大

    返回值-1 表示s1比s2的ASCII码小

char str1[] = "a";
char str2[] = "b";
printf("结果是%d\n", strcmp(str1, str2));   // -1
  1. strcpy(s1, s2) 字符串拷贝 拷贝后会覆盖原字符串且不能对字符串常量进行拷贝
char str1[] = "js";
printf("%s\n", strcpy(str1, "vue"));  // vuechar str2[] = "C语言";
strcpy(str2, "C++");
printf("%s\n", str2);  // c++
  1. strcat(s1, s2) 把字符串s2拼接到s1后。strcat在使用时s1与s2指的内存空间不能重叠,且s1要有足够的空间来容纳要复制的字符串
char str1[] = "hello ";
char str2[] = "world";
strcat(str1, str2);
printf("%s", str1);  // hello world
多维数组

定义一个二维数组 其中第一个[3]表示第一维下标的长度 第二个[3]表示第二维下标的长度

int num[3][3] = {{1,2,3},{4,5,6},{7,8,9}};

多维数组初始化必须指定列的维数,因为系统会根据数组中元素的总数来分配空间,当知道元素总数以及列的维数时,会自动计算出行的维数

多维数组遍历(循环嵌套)

综合练习

#include <stdio.h>
#define N 10
// 打印分数
void printScore(int score[])  // void函数中不需要有返回值
{int i;printf("\n");for(i=0; i<N; i++){printf("%d ", score[i]);}printf("\n");
}
// 计算总分
int getTotalScore(int score[])
{int sum = 0;int i;for(i=0; i<N; i++){sum += score[i];}return sum;
}
// 计算平均分
int getAvgScore(int score[])
{return getTotalScore(score)/N;
}
// 计算最高分
int getMax(int score[])
{int max = -1;int i;for(i=0; i<N; i++){if(score[i]>max){max = score[i];}}return max;
}
// 最低分
int getMin(int score[])
{int min = 100;int i;for(i=0; i<N; i++){if(score[i]<min){min = score[i];}}return min;
}
// 分数降序排序
void sort(int score[])
{int i, j;for(i=0; i<N-2; i++){for(j=0; j<=i; j++){if(score[j]<score[j+1]){int temp;temp = score[j];score[j] = score[j+1];score[j+1] = temp;}}}printScore(score);
}int main()
{int score[N]={67,98,75,63,82,79,81,91,66,84};int sum, avg, max, min;sum = getTotalScore(score);avg = getAvgScore(score);max = getMax(score);min = getMin(score);printf("总分是: %d\n", sum);printf("平均分是: %d\n", avg);printf("最高分是: %d\n", max);printf("最低分是: %d\n", min);printf("------------成绩排名------------\n");sort(score);return 0;
}

更新于2023.3.14

(未完待续…下一章:指针)

C语言入门 —— 非科班大一学生的C语言自学笔记相关推荐

  1. c语言实验报告常见问题,C语言新手问题~~我是大一学生上C语言课期末让写实验报告我呕心沥 爱问知识人...

    我是大一学生 上C语言课 期末让写实验报告 我呕心沥血写了半天的东西计算机死活不认 老师不给力 找老师也没帮我明确找出问题...我只能求助网络了...#include "Stdio.h&qu ...

  2. 但为君故——浅谈非科班大一在校大学生选择编程的心路历程。

    好的,先生们女士们大家好,如果您和我足够有道缘,如果我足够幸运,那么接下来您将看到的是一名非科班大一在校大学生选择编程的一段心路历程. 首先简单自我介绍一下,小生姓陈名奕涛,字幼彦,籍贯江苏,英文名是 ...

  3. c语言10个人 三向成绩,C语言入门学习精华:这样学习C语言最有效

    C语言入门学习精华:这样学习C语言最有效 c语言死了吗? 本材料描述了使用C语言的高级技能,并努力将您的C语言能力从"基本"提升到"高级".然而,学习态度比学习 ...

  4. R语言入门第二集 实验一:R 语言数据结构、数据导入与数据处理

    R语言入门第二集 实验一:R 语言数据结构.数据导入与数据处理 一.资源 R语言基本数据结构练习和数据的导入和处理对象常用函数练习--东北大学大数据班R语言实训第一次作业" R(4)求解数据 ...

  5. 大一怎么学好c语言_计算机专业大一学生,应该先学习哪门编程语言

    首先,对于计算机专业大一的同学来说,应该先从C语言开始学起,原因有三个方面,其一是C语言是面向过程式编程语言,比较简单易学,其二是掌握C语言对于学习后续的计算机专业课有较大的帮助,掌握C语言还可以通过 ...

  6. R语言必看推荐:R语言入门经典版(中文版)+R语言实战第二版(中文完整版)

    R语言入门经典(中文版)R for beginners R语言经典教材 第二版 适合初学者 作者:Emmanuel Paradis R 语言实战第二版(中文完整版) R语言实战(第2版)注重实用性,是 ...

  7. c语言入门1.2.3 百度云,C语言入门1.2.3--一个老鸟的C语言学习心得(附光盘)

    摘要: 本书是一本与众不同的C语言入门好书.作者以独特的视角,向初学者讲述了如何才能真正理解和掌握C语言.本书充分考虑了初学者学习C语言时的种种困难,讲解细致入微,抽丝剥茧,层层推进.本书除了讲述C语 ...

  8. c语言tab什么意思_C语言入门 — 一篇最全的C语言基础知识。

    c语言入门 C语言一经出现就以其功能丰富.表达能力强.灵活方便.应用面广等特点迅速在全世界普及和推广.C语言不但执行效率高而且可移植性好,可以用来开发应用软件.驱动.操作系统等.C语言也是其它众多高级 ...

  9. 《零基础看得懂的C语言入门教程 》——(十一)C语言自定义函数真的很简单

    一.学习目标 了解C语言的自定义函数的使用方法 了解C语言自定义函数的传参 了解C语言自定义函数的返回值 目录 C语言真的很难吗?那是你没看这张图,化整为零轻松学习C语言. 第一篇:(一)脱离学习误区 ...

最新文章

  1. 布局欧洲,挺进南美,比特币现金(BCH)再度攻下4个新市场
  2. Android中利用正则表达式验证手机号是否合法
  3. IOS – OPenGL ES 调节图像饱和度 GPUImageSaturationFilter
  4. 21 张让你代码能力突飞猛进的速查表(神经网络、线性代数、可视化等)
  5. matlab建立的发动机的模型,基于MATLAB∕Simulink的摩托车发动机仿真模型建立.pdf
  6. Vue3学习笔记01:使用NPM方法安装Vue3
  7. MFC添加View的方法
  8. 转发给上海的朋友们!程序员写了一款抢菜插件!这个抢菜插件让上海很多朋友成功抢了一个月的菜!感谢!...
  9. C# Access数据库使用
  10. C#中Panel控件的使用
  11. 十年游戏建模师给想学次世代游戏建模同学的一些忠告,太受益了
  12. mysql 短文本相似度_短文本相似度比较
  13. 第十一章 卡米洛特的黑暗时代
  14. 爬虫实战之爬取电影天堂全部电影信息
  15. 找规律填数字(c++基础)
  16. 美术 2.7 Metallic与Speculer流程
  17. solar2 android,solarwalk2
  18. python日期函数
  19. 下载谷歌play应用_选择在现有应用中使用Google Play应用签名
  20. VC++MFC应用程序向导

热门文章

  1. 高阶函数、委托与匿名方法
  2. Cannot mount AppImage, please check your FUSE setup.
  3. python使用Excel文件(增、删、改、查)
  4. 不同scheam下查询视图报错ORA-01031的故障解决
  5. linux自动生成证书,Linux生成TLS证书
  6. c语言break语句作用,解析c语言switch中break语句的具体作用
  7. 栅格布局一般怎么用_合理设置栅格化与比例 让版式布局更友好
  8. 用QT制作图片转换成ICO格式 领卓教育
  9. java对接 布防 海康威视_基于海康威视SDK javaB/S
  10. antv L7地图报错:context lost at Funciton