学习笔记 | C 程序设计基础


文章目录


C 程序设计基础

前言

    1. C语言用在哪里?
    • 操作系统
    • 嵌入式系统
    • 驱动程序
    • 底层驱动
  • 图形引擎、图像处理、声音效果

    1. C需要被编译才能运行
    • 编辑器
    • 编译器
  • 或者 IDE (集成开发环境)

    1. 推荐的编程软件

程序框架

程序结构

#include <stdio.h>
int main()
{
    return 0;
}

一个C语言程序的结构有以下特点:

(1)一个程序由一个或者多个源程序文件组成

在一个源程序文件中包括3部分:预处理指令、全局声明、函数定义

(2)函数是C语言程序的主要组成部分

(3)一个函数包括两个部分:函数首部和函数体,函数体又包括声明部分和执行部分

(4)程序总是从main函数开始之执行的

(5)程序中对计算机的操作是由函数中的C语句完成的

(6)在每个数据声明和语句的最后必须有一个分号

(7)C语言本身不提供输入输出语句

(8)程序应当包含注释

HelloWorld

#include <stdio.h>
int main()
{
    // 输出 Hello,World!
    printf("Hello,World!\n");
    return 0;
}
  • 命令行编辑、编译、运行程序

Example 01:

ls -l
gcc hello.c
ls -l
./a.out

Example 02:(默认在64位电脑上执行)

gcc hello.c -o hello
./hello

Example 03:(-m32 表示在32位电脑上执行)

gcc hello.c -o hello -m32
./hello

注释

    1. 单行注释://注释内容

​ 以//的单行注释,以换行符结束

    1. 多行注释:/* 注释内容 */

​ 这种注释可以跨越多行

注释内容可以用英文或者汉字

基本语法

数据的表现形式及其运算

1.常量

在程序运行过程中,其值不能被改变的量称为常量

常量有以下几类:

(1)整型常量:如1000,12345,0,-234等

(2)实型常量:十进制小数形式、指数形式

(3)字符常量:①普通字符,用单撇号括起来的一个字符,如’a’,‘Z’等 ②转义字符,如’’’,’\'等

(4)字符串常量:用双引号引起来的多个字符,如"China"等

(5)符号常量:用#define指令,指定用一个符号名称代表一个常量,如#define PI 3.1416

符号常量的优点:含义清楚、一改全改

2.变量

变量代表一个有名字的、具有特定属性的一个存储单元,它用来存放数据,也就是存放变量的值。在程序运行期间,变量的值是可以改变的。

变量必须先定义,后使用。

3.常变量

C99允许使用常变量:const int a=3;

常变量是有名字的不变量,而常量是没有名字的不变量。

常变量和符号常量有什么不同?

答:定义符号常量用#define指令,它是预编译指令,它知识用符号常量代表一个字符串,在预编译时仅是进行字符替换,在预编译后,符号常量就不存在了,对符号常量的名字是不分配存储单元的。而常变量要占用存储单元,有变量值,只是该值不改变。

4.标识符

标识符就是一个对象的名字。如变量名、函数名等等

C语言规定标识符只能由字母、数字和下划线3种字符组成,且第一个字符必须为字母或下划线。

数据类型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-79x2hHax-1583567038650)(https://wugenqiang.github.io/CS-Notes/images/20190112080640928.png)]

为char类型分配1字节,为int型数据分配4个字节。

(1)int型

  • 编译系统分配给int型数据2个字节或4个字节(VC++6.0就是分配4个字节)。

  • 在存储单元中的存储方式:用整数的补码形式存放。

  • int 表示一个寄存器的大小

(2)short int 型

  • 分配2个字节

(3)long int 型

  • 分配4个字节,在一个整数的末尾加大写字母L或小写字母l即可表示为long int型

(4)long long int 型

  • 分配8个字节

(5)字符类型

  • 分配1个字节

(6)float类型

  • 分配4个字节

(7)double类型

  • 分配8个字节

保留字

auto break case char const
continue default do double else
enum extern float for goto
if int long register return
short signed sizeof static struct
switch typedef union unsigned void
volatile while inline restrict

赋值和初始化

  • 变量初始化
  • <类型名称><变量名称> = <初始值>;
  • eg. int price = 0;

读整数

scanf("%d",&price);

举例:plus.c

#include "stdio.h" 

int main()
{
	int a = 0;
	int b = 0;
	
	printf("请输入两个整数:"); 
	scanf("%d %d",&a,&b);
	printf("%d + %d = %d\n",a,b,a + b);
	
	return 0; 
}
 

常量

  • 使用 const 定义常量,常量用大写字母表示
const int AMOUNT = 100;

运算符和算子

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SxRgW4bI-1583567038653)(https://wugenqiang.github.io/CS-Notes/images/image-20200224175745127.png)]

eg.
    int a = b + 5;
  • 计算时间差
#include "stdio.h" 
/*计算时间差*/ 
int main()
{
	int hour1, minute1;
	int hour2, minute2;
	
	scanf("%d %d", &hour1, &minute1);
	scanf("%d %d", &hour2, &minute2);
	
	int t1 = hour1 * 60 + minute1;
	int t2 = hour2 * 60 + minute2;
	
	int t = t2 - t1;
	
	printf("时间差是 %d 小时 %d 分钟。",t/60, t%60); 
	
	return 0; 
}
  • 运算符优先级

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oFq3anEa-1583567038656)(https://wugenqiang.github.io/CS-Notes/images/image-20200306092454286.png)]

自增、自减运算符:

     ++i 、--i :使用 i 之前,先使 i 的值加(减)1

     i++ 、i-- :在使用i之后,使 i 的值加(减)1

     自增、自减运算符只能用于变量,而不能用于常量或表达式。

强制类型转换运算符:

     (类型名)(表达式)

求字节数运算符:

     sizeof

数据的输入输出

scanf (格式输入)、printf (格式输出)

getchar (输入字符)、putchar (输出字符)

gets (输入字符串)、puts (输出字符串)

在使用它们之前需要在开头用预处理指令 #include <stdio.h>

printf 函数的一般格式

printf (格式控制,输出列表)

例如:printf (" %f 约等于 %d ", i , c );

类型安全

  • 强类型
  • 早期语言强调类型,面向底层的语言强调类型
  • C语言需要类型,但是对类型的安全检查并不足够

sizeof

  • 是一个静态运算符,给出某个类型或者变量在内存中所占据的字节数
  • sizeof(int)
  • sizeof(i)
  • Example 01:
#include <stdio.h>

int main()
{
	int a = 6;
	printf("sizeof(int)=%ld\n",sizeof(int));
	printf("sizeof(a)=%ld\n",sizeof(a));
	
    return 0;
}

补码

  • Example 01:
#include <stdio.h>

int main()
{
	char c = 255;
	int i = 255;
	printf("c=%d,i=%d\n",c,i);
	
    return 0;
}

unsigned

  • 无符号整数型(0-255)
  • 255u
  • 用 l 或 L 表示 long
  • unsigned 的初衷并非是扩展数能表达的范围,而是为了做纯二进制运算,主要是为了移位

整数的输入输出

  • 只有两种形式:int 或 long long

  • %d:int

  • %u:unsigned

  • %ld:long long

  • %lu:unsigned long long

  • Example 01:

#include <stdio.h>

int main()
{
	char c = -1;
	int i = -1;
	printf("c=%u,i=%u\n",c,i);
	
    return 0;
}
  • Example 02:八进制和十六进制转换为十进制
#include <stdio.h>

int main()
{
	char c = 012;//八进制 
	int i = 0x12;//十六进制 
	printf("c=%d,i=%d\n",c,i);
	
    return 0;
}
  • Example 03:八进制和十六进制输出
#include <stdio.h>

int main()
{
	char c = 012;//八进制 
	int i = 0x12;//十六进制 
	printf("c=0%o,i=0x%x\n",c,i);
	printf("c=0%o,i=0x%X\n",c,i);
	
    return 0;
}

浮点数的输入输出

  • float (4字节) 输入 %f 格式,输出 %f 或 %e

  • double (8字节)输入 %lf 格式,输出 %lf 或 %e

  • 科学计数法:-5.67E+16

  • 输出精度:

    • 在 % 和 f 之间加上 .n 可以指定输出小数点后几位,这样的输出是做4舍5入的
    • printf("%.3f\n",-0.0046);
#include <stdio.h>

int main()
{
	printf("%.3f\n",-0.0046);
	printf("%.30f\n",-0.0046);
	printf("%.3f\n",-0.00046);
	
    return 0;
}
  • 超过范围的浮点数:

    • printf 输出 inf 表示超过范围的浮点数:±∞
    • printf 输出 nan 表示不存在的浮点数
  • Example 01:

#include <stdio.h>

int main()
{
	printf("%f\n",12.0/0.0);
	printf("%f\n",-12.0/0.0);
	printf("%f\n",0.0/0.0);
	
    return 0;
}
  • 浮点运算的精度
    • f1 == f2 可能值相等,但不等
    • 利用 fabs(f1-f2)<1e-12

字符的输入输出

  • 如何输入 ‘1‘ 这个字符给 char c?

    • scanf("%c",&c);

    • #include <stdio.h>
      
      int main()
      {
      	char c;
      	scanf("%c",&c);
      	printf("c=%d\n",c);
      	printf("c=%c\n",c);
      	
          return 0;
      }
      
      
  • Example 01:

#include <stdio.h>

int main()
{
	char c;
	char d;
	c = 1;
	d = '1';
	if(c == d){
		printf("相等\n"); 
	}else{
		printf("不相等\n");
	}
	printf("c=%d\n",c);
	printf("d=%d\n",d);
	
    return 0;
}
  • 字母大小写转换
    • a+‘a’-‘A’ 大写字母变成小写字母
    • a+‘A’-‘a’ 小写字母变成大写字母

逃逸字符

字符 意义 字符 意义
\b 回退一格 \ " 双引号
\t 到下一个表格位 \ ’ 单引号
\n 换行 \ \ 反斜杠本身
\r 回车
  • Example 01:
#include <stdio.h>

int main()
{
	printf("123\bA\n456");
	
    return 0;
}

自动类型转换

  • 当运算符的两边出现不一致的类型时,会自动转换成较大的类型
  • char --> short --> int --> long --> long long
  • int --> float --> double
  • short ----- %hd
  • long ------ %ld

强制类型转换

  • Example 01:

  • (int)10.2

  • (short)32

  • 反例1:

  • #include <stdio.h>
    
    int main()
    {
    	printf("%d\n",(short)32768);
    	
        return 0;
    }
    
  • 结果:-32768

  • 反例2:

  • #include <stdio.h>
    
    int main()
    {
    	printf("%d\n",(char)32768);
    	
        return 0;
    }
    
  • 结果:0

注:强制类型转换的优先级高于四则运算

选择结构和条件判断

C语言有两种选择语句:

(1)if 语句,用来实现两个分支的选择结构

if (表达式)
    语句1
else
    语句2

(2)switch 语句,用来实现多分支的选择结构

switch(表达式)
{
case 常量1 :语句1
case 常量2 :语句2
        ...
case 常量n :语句n
default: 语句n+1

循环结构

(1)用while语句实现循环

while(表达式)
    语句

(2)用do…while 语句实现循环

do
    语句
while(表达式);

(3)用for语句实现循环

for(表达式1;表达式2;表达式3)
    语句
  • 改变循环执行的状态

(1)用break语句提前终止循环

一般形式:break;

注意:break语句还可以用来从循环体内跳出循环体,即提前结束循环,接着执行循环下面的语句。break语句只能用于循环语句和switch语句之中,而不能单独使用。

(2)用continue语句提前结束本次循环

一般形式:continue;

注:作用为结束本次循环,即跳过循环体中下面尚未执行的语句,转到循环体结束点之前,然后进行下一次是否执行循环的判定。

bool

  • #include <stdbool.h>
  • 之后就可以使用bool和true、false
#include <stdio.h>
#include <stdbool.h> 

int main()
{
	bool b = 6>5;
	printf("%d",b);
    
    return 0;
}

随机数

  • rand()
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//主函数 
int main(){
	
	srand(time(0));
	int a = rand();
	
	printf("%d\n",a);
	
	return 0;
}
  • x%n 的结果是[0,n-1]的一个整数
printf("%d\n",a%100);
#include <stdio.h>

int main()
{
	unsigned char c = 255;
	int i = 255;
	printf("c=%d,i=%d\n",c,i);
	
    return 0;
}

逻辑运算

运算符 描述 事例
逻辑非 !a
&& 逻辑与 a && b
|| 逻辑或 a || b

函数

  • 函数是一块代码,接收零个或多个参数,做一件事情,并返回零个或一个值

  • 函数原型,以分号结尾,即声明

  • Example 01:判断素数

    int isPrime(int i){
    	int result = 1;
    	int k;
    	for(k=2;k<i-1;k++){
    		if(i%k == 0){
    			result = 0;
    			break;
    		}
    	}
    	return result;
    }
    
  • Example 02:求和函数 ==> 求1到10、20到30和36到45的三个和

  • void sum(int begin,int end){
    	int i;
    	int sum = 0;
    	for(i=begin;i<=end;i++){
    		sum += i;
    	}
    	printf("%d 到 %d 的和是 %d\n",begin,end,sum);
    }
    
  • C 语言在调用函数时,永远只能传值给函数

局部变量

  • 也叫:本地变量 ==> 定义在函数内部的变量
  • 生存期和作用域 ==> 大括号内,即代码块

全局变量

  • 定义在函数体外面

避免代码复制 代码复制是代码不良的表现!

一维数组

数组大小

  • const int number = 10;
  • 使用 sizeof 给出整个数组所占据的内容的大小,单位是字节:sizeof(a)/sizeof(a[0])

初始化数组

  • for(i=0;i<number;i++){
    		count[i]=0;
    	}
    

集成初始化

int a[] = {2,4,6,7,1};
  • 集成初始化时的定位
int a[10] = {[0] = 2,[2] = 3,6,};

定义数组

  • < 类型 > 变量名称 [ 元素数量 ]

  • int number[100];

  • scanf("%d",&number[i]);

  • int grades[100];

  • double weight[20];

  • 元素数量必须是整数

  • 使用数组时放在[]中的数字叫做下标或索引,下标从0开始计数

  • 有效的下标范围

    • [ 0 , 数组的大小 - 1 ]

数组的赋值

注:数组变量本身不能被赋值,要把一个数组的所有元素交给另一个数组,必须采用遍历

for(i=0;i<length;i++){
    b[i] = a[i];
}

数组运算

  • 案例:代码训练 018
  • 案例:代码训练 019
  • 案例:代码训练 020
  • 案例:代码训练 021

遍历数组输出

for(i=0;i<number;i++){
    printf("%d:%d\n",i,count[i]);
}

二维数组

  • int a [ 3 ] [ 5 ] 理解为 a 是一个 3 行 5 列的矩阵

初始化

int a[][5] = {
    {0,1,2,3,4},
    {2,3,4,5,6},
}

注:列数必须给出

数组运算

  • 案例1:tic-tac-toe 游戏

指针

  • 就是保存地址的变量
  • %p 用来输出指针的值、输出地址符,以16进制的形式输出内存地址
int i;
int* p = &i;
int* p,q;
int *p,q;
int *p,*q;

指针变量

  • 指针变量的值是具有实际值的变量的地址
void f(int *p);

int i=0;
f(&i);
  • Example 01:
#include <stdio.h>

void f(int *p);
 
int main(){
	int i = 6;
	printf("&i=%p\n",&i);
	f(&i);
	 
	return 0;
}

void f(int *p){
	printf("p=%p\n",p);
}

指针应用场景

  • 场景一:交换两个变量的值 [ swap(&a,&b) ]
void swap(int *pa,int *pb){
    int t = *pa;
    *pa = *pb;
    *pb = t;
}
  • 场景二:求最大、最小值
void minmax(int a[],int len,int *min,int *max){
    int i;
    *min = *max = a[0];
    for(i=1;i<len;i++){
        if(a[i]<*min){
            *min = a[i];
        }
        if(a[i]>*max){
            *max = a[i];
        }
    }
}
  • 场景三:函数返回运算的状态,结果通过指针返回
#include <stdio.h>

int divide(int a,int b,int *result);
 
int main(){
	int a = 5;
	int b = 2;
	int c;
	if(divide(a,b,&c)){
		printf("%d/%d=%d\n",a,b,c);
	}
	 
	return 0;
}

int divide(int a,int b,int *result){
	int ret = 1;
	if(b == 0){
		ret = 0;
	}else{
		*result = a/b;
	}
}

注:数组变量是特殊的指针

  • 数组变量本身表达地址,所以
    • int a[10];int *p = a; // 无需用&取地址
    • a == &a[0]

指针计算

  • Example 01:
#include <stdio.h>
 
int main(){
	char ac[] = {0,1,2,3,4,5,6,7,8,9,};
	char *p = &ac[0];
	char *p1 = &ac[5];
	printf("p=%p\n",p);
	printf("p+1=%p\n",p+1);
	printf("p1-p=%d\n",p1-p);
	
	return 0;
}

*p++

  • *的优先级虽然高,但是没有++高

  • 取出p所指的那个数据来,完事之后顺便把p移到下一个位置去

  • Example 02:

#include <stdio.h>
 
int main(){
	char ac[] = {0,1,2,3,4,5,6,7,8,9,-1};
	char *p = &ac[0];
	int i;
	for(i=0;i<sizeof(ac)/sizeof(ac[0]);i++){
		printf("%d\n",ac[i]);
	}
	while(*p != -1){
		printf("%d\n",*p++);
	}
	
	return 0;
}

0地址

  • 内存中有0地址,但是不能随便碰
  • 0地址用来表示特殊的事情:
    • 返回的指针是无效的
    • 指针没有被真正初始化(先初始化为0)
  • NULL是一个预定定义的符号,表示0地址

动态内存分配

输入数据

  • int * a = (int *)malloc(n * sizeof(int))

  • 向 malloc 申请的空间的大小是以字节为单位的,返回的是void * ,需要类型转换为自己需要的类型

  • Example 01:

#include <stdio.h>
#include <stdlib.h> 

int main(){
	int number;
	int *a;
	int i;
	printf("输入数量:"); 
	scanf("%d",&number);
	a = (int *)malloc(number*sizeof(int));
	for(i=0;i<number;i++){
		scanf("%d",&a[i]);
	}
	for(i=number-1;i>=0;i--){
		printf("%d ",a[i]);
	}
    free(a);
    
	return 0;
}

字符串

字符数组:char word[] = {‘H’,‘e’,‘l’,‘l’,‘o’,’!’};

字符串:char word[] = {‘H’,‘e’,‘l’,‘l’,‘o’,’!’,’\0’};

  • 字符串以0结尾的一串字符,以数组的形式存在,以数组或指针的形式访问

字符串变量和常量

  • char * str = “Hello”;

  • char word[] = “Hello”;

  • char line[10] = “Hello”;

  • Example 01:

#include <stdio.h> 

int main(){
	char *s = "Hello World\0";
	char s1[] = "Hello World\0";
	s1[0] = 'B';
	
	printf("s=%s\n",s);
	printf("s1=%s\n",s1);
	printf("Here!s1[0]=%c\n",s1[0]); 
	return 0;
}

字符串输入输出

  • scanf 读入一个单词(到空格、tab或回车为止)
char string[8];
scanf("%s",string);
printf("%s",string);

空字符串

  • char buffer[100] = “”; //这是一个空的字符串,buffer[0] == ‘\0’;
  • char buffer[] = “”; //这个数组的长度只有1

字符串数组

字符串函数

putchar

  • int putchar(int c);
  • 向标准输出写一个字符
  • 返回写了几个字符,EOF(-1)表示写失败

getchar

  • int getchar(void)
  • 从标准输入读入一个字符
  • 返回类型时int是为了返回EOF(-1)
  • windows-----ctrl+Z
  • linux-----------ctrl+D

案例:

  • Example 01:
#include <stdio.h> 

int main(){
	int ch;
	while((ch = getchar()) != EOF){
		putchar(ch);
	}
	printf("EOF\n");
	
	return 0;
}

string.h 标准库中包含函数:

strlen

  • size_t strlen(const char *s);

  • 返回s的字符串长度(不包括结尾的0)

  • Example 01:

#include <stdio.h> 
#include <string.h>

int main(){
	char line[] = "Hello";
	printf("strlen=%lu\n",strlen(line));
	printf("sizeof=%lu\n",sizeof(line));
	
	return 0;
}
  • Example 02:用mylen自定义函数,替代库中strlen
#include <stdio.h> 
#include <string.h>

int mylen(const char *s){
	
	int idx = 0;
	while(s[idx]!='\0'){
		idx++;
	}
	return idx;
}

int main(){
	char line[] = "Hello";
	printf("strlen=%lu\n",mylen(line));
	printf("sizeof=%lu\n",sizeof(line));
	
	return 0;
}

strcmp

  • int strcmp(const char *s1,const char *s2);

  • 比较两个字符串,返回:

    • 0:s1 == s2
    • 1:s1 > s2
    • -1:s1 < s2
  • Example 01:

#include <stdio.h> 
#include <string.h>

int main(){
	char s1[] = "abc";
	char s2[] = "abc";
	printf("%d\n",strcmp(s1,s2));
	
	return 0;
}
  • Example 02:
#include <stdio.h> 
#include <string.h>

int main(){
	char s1[] = "abc";
	char s2[] = "Abc";
	printf("%d\n",strcmp(s1,s2));
	printf("%d\n",'a'-'A');
	
	return 0;
}
  • Example 03:
#include <stdio.h> 
#include <string.h>

int mycmp(const char *s1,const char *s2){
	int idx = 0;
	while(s1[idx] == s2[idx] && s1[idx] != '\0'){
//		if(s1[idx] != s2[idx]){
//			break;
//		}else if(s1[idx] == '\0'){
//			break;			
//		}
		idx++;
	}
	return s1[idx] - s2[idx];
}

int main(){
	char s1[] = "abc";
	char s2[] = "Abc";
	printf("%d\n",mycmp(s1,s2));
	printf("%d\n",'a'-'A');
	
	return 0;
}
  • Example 04:
#include <stdio.h> 
#include <string.h>

int mycmp(const char *s1,const char *s2){
		while(*s1 == *s2 && *s1 != '\0'){
		s1++;
		s2++;
	}
	return *s1 - *s2;
}

int main(){
	char s1[] = "abc";
	char s2[] = "Abc";
	printf("%d\n",mycmp(s1,s2));
	printf("%d\n",'a'-'A');
	
	return 0;
}

strcpy

  • char *strcpy(char *restrict dst, const char *restrict src);
  • 把src的字符串拷贝到dst
  • restrict表明src和dst不重叠(C99)
  • 返回dst,为了能链起代码

复制一个字符串

//动态申请内存
char *dst = (char*)malloc(strlen(src)+1);
//拷贝src到dst
strcpy(dst,src);
  • Example 01:自定义版本----数组
#include <stdio.h> 
#include <string.h>

int mycpy(char *dst,char *src){
	int idx = 0;
	while(src[idx]){
		dst[idx] = src[idx];
		idx++;
	}
	//dst[idx] = src[idx];
	dst[idx] = '\0';
	return dst;
}

int main(){
	char s1[] = "abc";
	char s2[] = "Abc";
	printf("%s\n",strcpy(s1,s2));
	
	return 0;
}
  • Example 02:自定义版本----指针
#include <stdio.h> 
#include <string.h>

int mycpy(char *dst,char *src){
	char *ret = dst;
//	while(*src){
////		*dst = *src;
////		dst++;
////		src++;
//		*dst++ = *src++;	
//	}	
	while(*dst++ = *src++){
	}	
	*dst = '\0';
	return ret;
}

int main(){
	char s1[] = "abc";
	char s2[] = "Abc";
	printf("%s\n",strcpy(s1,s2));
	
	return 0;
}

strcat

  • char *strcat(char *restrict s1, const char *restrict s2);

  • 把s2拷贝到s1的后面,接成一个长的字符串

  • 返回s1

  • s1必须具有足够的空间

strchr

  • 在字符串中找字符

  • char * strchr(const char *s,int c);

  • 返回NULL表示没有找到

  • Example 01:

#include <stdio.h> 
#include <string.h>

int main(){
	char s[] = "hello";
	char *p = strchr(s,'l');
	p = strchr(p+1,'l');
	printf("%s\n",p);
	
	return 0;
}
  • Example 02:
#include <stdio.h> 
#include <string.h>

int main(){
	char s[] = "hello";
	char *p = strchr(s,'l');
	char *t = (char*)malloc(strlen(p)+1);
	strcpy(t,p);
	printf("%s\n",t);
	free(t);
	
	return 0;
}
  • Example 03:
#include <stdio.h> 
#include <string.h>

int main(){
	char s[] = "hello";
	char *p = strchr(s,'l');
	char c = *p;
	*p = '\0';
	
	char *t = (char*)malloc(strlen(s)+1);
	strcpy(t,s);
	printf("%s\n",t);
	free(t);
	
	return 0;
}

strrchr

  • Example 01:
#include <stdio.h> 
#include <string.h>

int main(){
	char s[] = "hello";
	char *p = strchr(s,'l');
	p = strrchr(p,'l');
	printf("%s\n",p);
	
	return 0;
}

strstr

  • 字符串中找字符串
  • char *strstr(const char *s1, const char *s2);
  • char *strcasestr(const char *s1, const char *s2);

安全问题

  • 要考虑

结构类型

枚举

用枚举优化常量符号化,变得更加方便

  • enum 枚举类型名字{名字0,…,名字n};

  • Example 01:

#include <stdio.h> 

enum color{
	red,
	yellow,
	green
};

void f(enum color c);

int main(){
	enum color t = red;
	scanf("%d",&t);
	f(t);
	
	return 0;
}

void f(enum color c){
	printf("%d\n",c);
}

枚举量

  • 声明枚举量的时候可以指定值

  • enum color{
    	red = 1,
    	yellow,
    	green = 5
    };
    

枚举只是int

实际上很少用

结构体

声明结构类型

  • Example 01:
#include <stdio.h> 

struct date{
		int month;
		int day;
		int year;
	};
	
int main(){
	struct date today;
	today.month = 03;
	today.day = 05;
	today.year = 2020;
	printf("%i-%i-%i",today.year,today.month,today.day);
	//%i表示有符号十进制整数 
	return 0;
}

声明结构的形式

  • 形式一:
struct point{
    int x;
    int y;
};
struct point p1,p2;	// p1和p2都是point里面有x和y的值

  • 形式二:
struct{
    int x;
    int y;
}p1,p2;// p1和p2都是一种无名结构,里面有x和y
  • 形式三:(推荐)
struct point{
    int x;
    int y;
}p1,p2;
// p1和p2都是point里面有x和y的值

结构变量

struct date today;
today.month = 03;
today.day = 05;
today.year = 2020;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bEcZFWPP-1583567038660)(https://wugenqiang.github.io/CS-Notes/images/image-20200306092007788.png)]

结构体的初始化

struct date today = {03,05,2020};

结构成员

today.day

结构运算

  • 赋值、取地址、传递函数参数

  • p1 = (struct point){5,10}; //相当于p1.x = 5,p1.y = 10;

  • p1 = p2; //相当于p1.x = p2.x; p1.y = p2.y;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x5810ZU2-1583567038661)(https://wugenqiang.github.io/CS-Notes/images/image-20200306092110362.png)]

结构可作为函数参数

bool isLeap(struct date d);

结构指针作为参数

  • 指向结构的指针
struct date{
    int month;
    int day;
    int year;
}myday;
struct date *p = &myday;
(*p).month = 12;
p -> month = 12;

用->表示指针所指的结构变量中的成员

结构数组

struct date dates[100];
struct date dates[] = {{4,5,2005},{2,4,2005}};

结构中的结构

struct dateAndTime{
    struct date sdate;
    struct time stime;
}
  • Example 01:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hLo0dzky-1583567038662)(https://wugenqiang.github.io/CS-Notes/images/image-20200306092200846.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6SIbez2q-1583567038663)(https://wugenqiang.github.io/CS-Notes/images/image-20200306092243437.png)]

Typedef

  • typedef 自定义数据类型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CYWGmJ6z-1583567038664)(https://wugenqiang.github.io/CS-Notes/images/image-20200306092323697.png)]

  • typedef struct{
        int month;
        int day;
        int year;
    }Date;
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H52j6mCC-1583567038666)(https://wugenqiang.github.io/CS-Notes/images/image-20200305211317278.png)]

联合体

union AnElt{
    int i;
    char c;
}elt1,elt2;
elt1.i = 4;
elt2.c = 'a';
  • sizeof(union …) = // sizeof (每个成员) 的最大值
#include <stdio.h> 

typedef union{
	int i;
	char ch[sizeof(int)];
}Data;

int main(){
	Data data;
	int i;
	data.i = 1234;
	for(i=0;i<sizeof(int);i++){
		//对于%02hhx,hhx已经以一个字节打印了,加上02限制,不够两位的补成两位。 
		printf("%02hhX",data.ch[i]);
	}
	printf("\n");
	
	return 0;
}

程序结构

全局变量

全局变量初始化

  • 默认初始化为0,指针会得到NULL
  • 尽量不要使用全局变量来在函数间传递参数和结果

静态本地变量

  • static

  • 使用全局变量和静态本地变量的函数是线程不安全的

编译预处理和宏

编译预处理指令

  • #开头的是编译预处理指令

  • 它们不是c语言的成分,但是c语言程序离不开它们

  • #define 用来定义一个宏,原始的文本替换

  • Example 01:

    • #include <stdio.h> 
      //const double PI = 3.14159; 
      #define PI 3.14159
      
      int main(){
      	
      	printf("%f\n",2*PI);
      	
      	return 0;
      }
      
  • Example 02:

    • #include <stdio.h> 
      //const double PI = 3.14159; 
      #define PI 3.14159
      #define PI2 2*PI  // PI * 2
      #define PRT printf("%f ",PI); \
      			printf("%f\n",PI2)
      
      int main(){
      	
      //	printf("%f\n",PI);
      //	printf("%f\n",PI2);
      	PRT;
      	
      	return 0;
      }
      

#define

  • 有值的宏:参考上面 Example 02
  • 没有值的宏:#define _DEBUG // 这类宏适用于条件编译,后面有其他的编译预处理指令来检查这个宏是否已经被定义过了

预定义的宏

  • _ _ LINE _ _

  • _ _ FILE _ _

  • _ _ DATE _ _

  • _ _ TIME _ _

  • _ _ STDC _ _

  • Example 01:

    • #include <stdio.h> 
      
      int main(){
      	printf("%s:%d\n",__FILE__,__LINE__);
      	printf("%s:%s\n",__DATE__,__LINE__);
      	
      	return 0;
      }
      

像函数的宏

  • #define cube(x) ( (x) * (x) * (x) )

  • 宏可以带参数

  • Example 01:

    • #include <stdio.h> 
      
      #define cube(x) ((x)*(x)*(x)) 
      
      int main(int argc,char const *argv[]){
      	int i;
      	scanf("%d",&i);
      	printf("%d\n",cube(i));
      	
      	return 0;
      }
      
  • 带参数的宏的原则:

    • 一切都要括号
      • 整个值要括号
      • 参数出现的每个地方都要括号
    • #define RADTODEG(x) ( (x) * 57.29578 )
  • 宏可以带多个参数:

    • #define MIN(a,b) ((a)>(b)?(b):(a))
  • 宏也可以组合(嵌套)使用其他宏

大程序结构

多个 .c 文件

  • 在 Dev C++ 中新建一个项目,然后把几个源代码文件加入进去,然后编译和构建运行即可。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KazBNKBl-1583567038668)(https://wugenqiang.github.io/CS-Notes/images/image-20200306171635923.png)]

  • 编译单元

    • 一个 .c 文件是一个编译单元
    • 编译器每次编译只处理一个编译单元
  • 引入头文件

    • 把函数原型放在一个头文件(以 .h 结尾)中,在需要调用这个函数的源代码文件( .c 文件)中 #include 这个头文件,就可以让编译器在编译的时候知道函数的原型。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-At4eayTs-1583567038673)(https://wugenqiang.github.io/CS-Notes/images/image-20200306173027863.png)]

声明

在 .h 中添加 extern int gAll; 就能使用 gAll 了

  • int i; //是变量的定义

  • extern int i; //是变量的声明

  • 声明不产生代码,定义产生代码

  • 声明包括:

    • 函数原型
    • 变量声明
    • 结构声明
    • 宏声明
    • 枚举声明
    • 类型声明
    • inline 声明
  • 只有声明才能放在头文件中

标准头文件结构

  • 条件编译指令

  • #ifndef _ MAX_H _ //如果没有定义

  • #define _ MAX_H _ //则定义

  • #endif

  • 避免了重复引用的情况

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QnfHjpso-1583567038674)(https://wugenqiang.github.io/CS-Notes/images/image-20200306175006974.png)]

文件

文件输入输出

  • linux 用 > 和 < 做重定向

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0npSeVUc-1583567038676)(https://wugenqiang.github.io/CS-Notes/images/image-20200306180200439.png)]

  • 打开文件的标准代码:

    • FILE *fp = fopen("file","r");
      if(fp){
          fscanf(fp,...);
          fclose(fp);
      }else{
          ...
      }
      
    • Example 01:

    • #include <stdio.h> 
      
      int main(int argc,char const *argv[]){
      	FILE *fp = fopen("12.in","r");
      	if(fp){
      		int num;
      		fscanf(fp,"%d",&num);
      		printf("%d\n",num);
      		fclose(fp);
      	} else{
      		printf("无法打开文件\n");
      	}
      	
      	return 0;
      }
      

fopen

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QrjKfBiv-1583567038678)(https://wugenqiang.github.io/CS-Notes/images/image-20200306181622981.png)]

二进制文件

  • 其实所有的文件最终都是二进制的
  • 文本文件读写:
    • more、tail
    • cat
    • vi
  • 二进制文件需要专门的程序来读写
  • 文本文件的输入输出是格式化,可能经过转码

文件练习题

文件练习举例:

  • Example 01:

    • student.h

    • #ifndef _STUDENT_H_
      #define _STUDENT_H_
      
      //const int STR_LEN = 20;
      #define STR_LEN 20
      
      typedef struct _student{
      	char name[STR_LEN];
      	int gender;
      	int age;
      }Student;
      
      #endif
      
    • main.c

    • #include <stdio.h>
      #include "student.h"
      
      void getList(Student aStu[],int number);
      int save(Student aStu[],int number);
      
      int main(int argc, char *argv[]) {
      	int number = 0;
      	printf("输入学生数量:");
      	scanf("%d",&number);
      	Student aStu[number];
      	
      	getList(aStu,number);
      	if(save(aStu,number)){
      		printf("保存成功\n");
      	}else{
      		printf("保存失败\n");
      	}
      	
      	return 0;
      }
      
      void getList(Student aStu[],int number){
      	char format[STR_LEN];
      	//向字符串输出 
      	sprintf(format,"%%%ds",STR_LEN-1);
      	//%19s 
      	int i;
      	for(i=0;i<number;i++){
      		printf("第%d个学生:\n",i);
      		printf("\t姓名:");
      		scanf(format,aStu[i].name); 
      		printf("\t性别(0-男,1-女,2-其他):");
      		scanf("%d",&aStu[i].gender);
      		printf("\t年龄:");
      		scanf("%d",&aStu[i].age); 
      	}
      }
      
      int save(Student aStu[],int number){
      	int ret = -1;
      	FILE *fp = fopen("student.data","w");
      	if(fp){
      		ret = fwrite(aStu,sizeof(Student),number,fp);
      		fclose(fp);
      	}
      	return ret == number;
      }
      
  • 测试结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RBwloA5Y-1583567038681)(https://wugenqiang.github.io/CS-Notes/images/image-20200306204450498.png)]

在文件中定位

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r7Jm1kIO-1583567038684)(https://wugenqiang.github.io/CS-Notes/images/image-20200306204846477.png)]

  • Example 02:

    • read.c

    • #include <stdio.h>
      #include "student.h"
      
      void read(FILE *fp,int index);
      
      int main(){
      	FILE *fp = fopen("student.data","r");
      	if(fp){
      		fseek(fp,0L,SEEK_END);
      		long size = ftell(fp);
      		int number = size / sizeof(Student);
      		int index = 0;
      		printf("有%d个数据,你要看第几个:",number);
      		scanf("%d",&index);
      		read(fp,index-1);
      		fclose(fp);
      	}
      	return 0;	
      }
      
      void read(FILE *fp,int index){
      	fseek(fp,index * sizeof(Student),SEEK_SET);
      	Student stu;
      	if(fread(&stu,sizeof(Student),1,fp) == 1){
      		printf("第%d个学生:",index+1);
      		printf("\t姓名:%s\n",stu.name);
      		printf("\t性别:");
      		switch(stu.gender) {
      			case 0:printf("男\n");break;
      			case 1:printf("女\n");break;
      			case 2:printf("其他\n");break;
      		}
      		printf("\t年龄:%d\n",stu.age);
      	}
      }
      
  • Test Result:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rDjTQB2x-1583567038685)(https://wugenqiang.github.io/CS-Notes/images/image-20200306210748268.png)]

  • 可移植性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x5bGeWjV-1583567038686)(https://wugenqiang.github.io/CS-Notes/images/image-20200306211106200.png)]

位运算

按位运算

  • C 有这些按位运算的运算符:
    • & 按位与
    • | 按位或
    • ~ 按位取反
    • ^ 按位异或
    • << 左移
    • >> 右移

移位运算

  • 按位运算输出 int

  • 左移

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LY73ikxN-1583567038687)(https://wugenqiang.github.io/CS-Notes/images/image-20200306212541735.png)]

  • 右移

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HyvQrRHK-1583567038689)(https://wugenqiang.github.io/CS-Notes/images/image-20200306212636652.png)]

注:移位的位数不要用负数,这是没有定义的行为

位段

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fj67YKO2-1583567038694)(https://wugenqiang.github.io/CS-Notes/images/image-20200306213148645.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RnIR0L46-1583567038696)(https://wugenqiang.github.io/CS-Notes/images/image-20200306213254105.png)]

链表

可变数组

  • Example 01:

    • array.h

    • #ifndef _ARRAY_H_
      #define _ARRAY_H_
      
      typedef struct {
      	int *array;
      	int size;
      }Array;
      
      #define BLOCK_SIZE 20
      
      Array array_create(int init_size);
      void array_free(Array *a);
      int array_size(const Array *a);
      int *array_at(Array *a,int index);
      void array_inflate(Array *a,int more_size);
      int array_get(const Array *a,int index);
      void array_set(Array *a,int index,int value);
      
      #endif
      
    • array.c

    • #include "array.h"
      #include <stdio.h>
      #include <stdlib.h>
      
      //typedef struct {
      //	int *array;
      //	int size;
      //}Array;
      
      Array array_create(int init_size){
      	Array a;
      	a.size = init_size;
      	a.array = (int *)malloc(sizeof(int)*a.size);
      	return a;
      }
      void array_free(Array *a){
      	free(a->array);
      	a->array = NULL;
      	a->size = 0;
      }
      int array_size(const Array *a){
      	return a->size;
      }
      int *array_at(Array *a,int index){
      	if(index>=a->size){
      		//array_inflate(a,index-a->size+1);
      		array_inflate(a,(index/BLOCK_SIZE +1)*BLOCK_SIZE-a->size);
      	}
      	return &(a->array[index]);
      }
      //可变字符自动按块增长 
      void array_inflate(Array *a,int more_size){
      	int *p = (int *)malloc(sizeof(int)*(a->size + more_size));
      	int i;
      	for(i=0;i<a->size;i++){
      		p[i] = a->array[i];
      	}
      	free(a->array);
      	a->array = p;
      	a->size += more_size;
      }
      int array_get(const Array *a,int index){
      	return a->array[index];
      }
      
      void array_set(Array *a,int index,int value){
      	a->array[index] = value;
      }
      
      int main(){
      	Array a = array_create(100);
      	printf("%d\n",array_size(&a));
      	printf("%d\n",a.size);
      	*array_at(&a,0) = 10;
      	printf("%d\n",*array_at(&a,0));
      	int number;
      	int cnt = 0;
      	while(number != -1){
      		scanf("%d",&number);
      		if(number!=-1){
      			*array_at(&a,cnt++) = number;
      		}
      	} 
      	
      	array_free(&a);
      	
      	return 0;
      }
      

可变数组的缺陷

  • 要 copy,不能充分利用

链表存储数据

链表存储数据 add

  • Example 01:
#include <stdio.h> 
#include <stdlib.h>

typedef struct _node{
	int value;
	struct _node *next;
	
}Node; 

int main(){
	Node *head = NULL;
	int number;
	do{
		scanf("%d",&number);
		if(number != -1){
			//	add to linkList
			Node *p = (Node*)malloc(sizeof(Node));
			p->value = number;
			p->next = NULL;
			//	find the last
			Node *last = head;
			if(last){
				while(last->next){
			    	last = last->next;
				}
				//	attach
				last->next = p;
			}else{
				head = p;
			}
		}
	} while(number != -1);
	
	return 0;
}
  • Example 02:对 01 进行改进
#include <stdio.h> 
#include <stdlib.h>

typedef struct _node{
	int value;
	struct _node *next;
	
}Node; 

Node* add(Node *head, int number);

int main(){
	Node *head = NULL;
	int number;
	do{
		scanf("%d",&number);
		if(number != -1){
			head = add(head,number);
		}
	} while(number != -1);
	
	return 0;
}

Node* add(Node *head, int number){
	//	add to linkList
	Node *p = (Node*)malloc(sizeof(Node));
	p->value = number;
	p->next = NULL;
	//	find the last
	Node *last = head;
	if(last){
		while(last->next){
	    	last = last->next;
		}
		//	attach
		last->next = p;
	}else{
		head = p;
	}
	return head;
}
  • Example 02:对 01 进行改进
#include <stdio.h> 
#include <stdlib.h>

typedef struct _node{
	int value;
	struct _node *next;
	
}Node; 

Node* add(Node **pHead, int number);

int main(){
	Node *head = NULL;
	int number;
	do{
		scanf("%d",&number);
		if(number != -1){
			head = add(&head,number);
		}
	} while(number != -1);
	
	return 0;
}

Node* add(Node **pHead, int number){
	//	add to linkList
	Node *p = (Node*)malloc(sizeof(Node));
	p->value = number;
	p->next = NULL;
	//	find the last
	Node *last = *pHead;
	if(last){
		while(last->next){
	    	last = last->next;
		}
		//	attach
		last->next = p;
	}else{
		*pHead = p;
	}
	return *pHead;
}
  • Example 03:对 02 进行改进
#include <stdio.h> 
#include <stdlib.h>

typedef struct _node{
	int value;
	struct _node *next;
	
}Node; 

typedef struct _list{
	Node *head;
}List; 

void add(List *pList, int number);

int main(){
	List list;
	list.head = NULL;
	int number;
	do{
		scanf("%d",&number);
		if(number != -1){
			add(&list,number);
		}
	} while(number != -1);
	
	return 0;
}

void add(List *pList, int number){
	//	add to linkList
	Node *p = (Node*)malloc(sizeof(Node));
	p->value = number;
	p->next = NULL;
	//	find the last
	Node *last = pList->head;
	if(last){
		while(last->next){
	    	last = last->next;
		}
		//	attach
		last->next = p;
	}else{
		pList->head = p;
	}
}
  • Example 04:对 03 进行改进
typedef struct _node{
	int value;
	struct _node *next;
	
}Node; 

typedef struct _list{
	Node *head;
	Node *tail;
}List; 

void add(List *pList, int number);

int main(){
	List list;
	list.head = list.tail = NULL;
	int number;
	do{
		scanf("%d",&number);
		if(number != -1){
			add(&list,number);
		}
	} while(number != -1);
	
	return 0;
}

待完善:list.tail

链表输出数据

链表输出数据 print

  • Example 01:
#include <stdio.h> 
#include <stdlib.h>

typedef struct _node{
	int value;
	struct _node *next;
	
}Node; 

typedef struct _list{
	Node *head;
	Node *tail;
}List; 

void add(List *pList, int number);

int main(){
	List list;
	list.head = list.tail = NULL;
	int number;
	do{
		scanf("%d",&number);
		if(number != -1){
			add(&list,number);
		}
	} while(number != -1);
	Node *p;
	//遍历输出 
	for(p=list.head;p;p=p->next){
		printf("%d\t",p->value);
	}
	printf("\n");
	
	return 0;
}

void add(List *pList, int number){
	//	add to linkList
	Node *p = (Node*)malloc(sizeof(Node));
	p->value = number;
	p->next = NULL;
	//	find the last
	Node *last = pList->head;
	if(last){
		while(last->next){
	    	last = last->next;
		}
		//	attach
		last->next = p;
	}else{
		pList->head = p;
	}
}
  • Example 02:对 01 进行优化
#include <stdio.h> 
#include <stdlib.h>

typedef struct _node{
	int value;
	struct _node *next;
	
}Node; 

typedef struct _list{
	Node *head;
	//Node *tail;
}List; 

void add(List *pList, int number);
void print(List *pList);

int main(){
	List list;
	list.head = NULL;
	int number;
	do{
		scanf("%d",&number);
		if(number != -1){
			add(&list,number);
		}
	} while(number != -1);
	print(&list); 
	
	return 0;
}

void add(List *pList, int number){
	//	add to linkList
	Node *p = (Node*)malloc(sizeof(Node));
	p->value = number;
	p->next = NULL;
	//	find the last
	Node *last = pList->head;
	if(last){
		while(last->next){
	    	last = last->next;
		}
		//	attach
		last->next = p;
	}else{
		pList->head = p;
	}
}

void print(List *pList){
	Node *p;
	//遍历输出 
	for(p=pList->head;p;p=p->next){
		printf("%d\t",p->value);
	}
	printf("\n");
}
  • Test Result

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M6aM3Dqi-1583567038698)(https://wugenqiang.github.io/CS-Notes/images/image-20200307142325721.png)]

链表查找数据并删除

链表查找数据并删除

  • Example 01:
#include <stdio.h> 
#include <stdlib.h>

typedef struct _node{
	int value;
	struct _node *next;
	
}Node; 

typedef struct _list{
	Node *head;
	//Node *tail;
}List; 

void add(List *pList, int number);
void print(List *pList);

int main(){
	List list;
	list.head = NULL;
	int number;
	do{
		scanf("%d",&number);
		if(number != -1){
			add(&list,number);
		}
	} while(number != -1);
	print(&list); 
	
	//查找数据 
	scanf("%d",&number);
	Node *p;
	int isFound = 0;
	for(p=list.head;p;p=p->next){
		if(p->value == number){
			printf("找到了\n");
			isFound = 1;
			break;
		}
	}
	if(!isFound){
		printf("没有找到\n");
	}
	
	//删除某个数据 
	Node *q;
	for(q=NULL,p=list.head;p;q=p,p=p->next){
		if(p->value == number){
			if(q){
				q->next = p->next;
			}else{
				list.head = p->next;
			}
			
			free(p);
			break;
		}
	} 
	
	//删除所有数据
	for(p=list.head;p;p=q){
		q = p->next;
		free(p);
	} 
	
	return 0;
}

void add(List *pList, int number){
	//	add to linkList
	Node *p = (Node*)malloc(sizeof(Node));
	p->value = number;
	p->next = NULL;
	//	find the last
	Node *last = pList->head;
	if(last){
		while(last->next){
	    	last = last->next;
		}
		//	attach
		last->next = p;
	}else{
		pList->head = p;
	}
}

void print(List *pList){
	Node *p;
	//遍历输出 
	for(p=pList->head;p;p=p->next){
		printf("%d\t",p->value);
	}
	printf("\n");
}

代码训练

001 逆序的三位数

【题目】

程序每次读入一个正三位数,然后输出逆序的数字。

注意,当输入的数字含有结尾的 0 时,输出不应带有前导的 0 。比如输入 700 ,输出应该是 7 。

提示:用 %10 可以得到个位数,用 /100 可以得到百位数…。将这样得到的三个数字合起来:百位 * 100 + 十位 * 10 + 个位,就得到了结果。

【输入格式】

每个测试是一个3位的正整数。

【输出格式】

输出逆序的数。

【输入样例】

123

【输出样例】

321

【时间限制】

500ms内存限制:32000kb

【参考代码】

  • C 版
#include <stdio.h>
int main()
{
    int t1,t2,mt1,mt2,mt3;
    
    scanf("%d",&t1);	//输入
     
    mt1=t1/100; mt2=(t1-mt1*100)/10; mt3=t1%10;
    t2=mt3*100+mt2*10+mt1;
    
    printf("%d\n",t2);	//输出
     
    return 0;
}

002 数位数

  • Example 01:先判断后执行
int main()
{
	int x;
	int count = 0;
	
	printf("请输入一个任意数:"); 
	scanf("%d",&x); 
	
	count++;
	x /= 10;
	while(x > 0)
	{
		count++;
		x /= 10;
	}
	
	printf("该数有 %d 位!\n",count);
    
    return 0;
}
  • Example 02:先执行后判断
#include <stdio.h>
//数位数 
int main()
{
	int x;
	int count = 0;
	
	printf("请输入一个任意数:"); 
	scanf("%d",&x); 
	
	do
	{
		x /= 10;
		count++;
	}while(x>0);
	
	printf("该数有 %d 位!\n",count);
    
    return 0;
}

003 求阶乘n!

【题目】写一个程序,让用户输入n,然后计算输出n!
【代码】

  • Example 01:
#include <stdio.h>
//求阶乘n! 
//题目:写一个程序,让用户输入n,然后计算输出n! 
int main()
{
	int n;
	int i=1;
	int fact = 1;//阶乘 
	
	printf("请输入一个任意数n:"); 
	scanf("%d",&n); 
	
/*	while(i<=n)
	{
		fact *= i; 
		i++;
	}*/
	for(i=2;i<=n;i++)
	{
		fact *= i; 
	}
	
	printf("%d!= %d\n",n,fact);
    
    return 0;
}
  • Example 02:
#include <stdio.h>

int main()
{
	int n;
	int i=1;
	int fact = 1;//阶乘 
	
	printf("请输入一个任意数n:"); 
	scanf("%d",&n); 
	
	for(i=n;i>1;i--)
	{
		fact *= i; 
	}
	
	printf("%d!= %d\n",n,fact);
    
    return 0;
}

004 猜数游戏

【题目】系统随机生成数字,猜数字

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//主函数 
int main(){
	
	srand(time(0));
	int number = rand()%100 + 1;//[0,100]
	int count = 0;
	int a = 0;
	
	printf("我已经想好了一个1到100之间的数。");
	 
	do{
		printf("请猜这个1到100之间的数:");
		scanf("%d",&a);
		
		count++;
		if(a>number){
			printf("你猜的数大了\n"); 
		} else if(a<number){
			printf("你猜的数小了\n"); 
		}
	}while(a!=number);
	
	printf("太好了,你用了 %d 次就猜到了答案。\n",count);
	
	return 0;
}

005 整数逆序

  • 001 逻辑一样,但是这个地方用到了循环结构
#include <stdio.h>

//主函数 
int main(){
	
	int x,digit;
	int result = 0;
	
	scanf("%d",&x);
	
	while(x>0){
		digit = x%10;
		result = result*10 + digit;
		x /= 10;
	}
	
	printf("%d",result);
	
	return 0;
}

006 判断素数

  • Example 01
#include <stdio.h>

//主函数 
int main(){
	
	int x;
	int i;
	
	scanf("%d",&x);
	
	for(i=2;i<x;i++){
		if(x%i == 0){
			break;
		}
	}
	
	if(i<x){
		printf("%d 不是素数",x);
	}else{
		printf("%d 是素数",x);
	}
	
	return 0;
}
  • Example 02
#include <stdio.h>

//主函数 
int main(){
	
	int x;
	int i;
	int isPrime = 1;
	
	scanf("%d",&x);
	
	for(i=2;i<x;i++){
		if(x%i == 0){
			isPrime = 0;
            break;
		}
	}
	
	if(isPrime == 1){
		printf("%d 是素数",x);
	}else{
		printf("%d 不是素数",x);
	}
	
	return 0;
}
  • Example 03:使用子函数调用的方式:去掉偶数,从3到x-1,每次加2
int isPrime(int x){
    int result = 1;
    int i;
    if(x == 1 || (x%2 == 0 && x != 2)){
        result = 0;
    }
    for(i=3;i<x;i+=2){
        if(x%i == 0){
            result = 0;
            break;
        }
    }
    return result;
}
  • Example 04:无须到x-1,到sqrt(x)就够了
int isPrime(int x){
    int result = 1;
    int i;
    if(x == 1 || (x%2 == 0 && x != 2)){
        result = 0;
    }
    for(i=3;i<sqrt(x);i+=2){
        if(x%i == 0){
            result = 0;
            break;
        }
    }
    return result;
}

注:sqrt(x) 返回类型 double,引入 #include <math.h>

  • Example 05:判断是否能被已知的且<x的素数整除
#include <stdio.h>

int isPrime(int x,int knownPrimes[],int numberOfKnownPrimes);

int main(){
	
	const int number = 100;
	int prime[number];
	prime[0] = 2;
	int j;
	for(j=1;j<number;j++){
		prime[j] = 0;
	}
	int count = 1;
	int i = 3;
	while(count < number){
		if(isPrime(i,prime,count)){
			prime[count++] = i;
		}
		i++;
	} 
	for(i=0;i<number;i++){
		printf("%d",prime[i]);
		if((i+1)%5){
			printf("\t");
		}else{
			printf("\n");
		}
	}
	
	return 0;
}

int isPrime(int x,int knownPrimes[],int numberOfKnownPrimes){
	int result = 1;
	int i;
	for(i=0;i<numberOfKnownPrimes;i++){
		if(x%knownPrimes[i]==0){
			result = 0;
			break;
		}
	}
	return result; 
}

007 输出100以内的素数

#include <stdio.h>

//主函数 
int main(){
	
	int x;
	
	for(x=2;x<100;x++){
		int i;
		int isPrime = 1;
		for(i=2;i<x;i++){
			if(x%i == 0){
				isPrime = 0;
				break;
			}
		}
	
		if(isPrime==1){
			printf("%d ",x);
		}
	}
	printf("\n");
		
	return 0;
}

008 凑硬币

【题目】如何用1角、2角和5角的硬币凑出10元以下的金额呢?

【代码】

#include <stdio.h>

//主函数 
int main(){
	
	int x;
	int one,two,five;
	
	scanf("%d",&x);
	
	for(one=1;one<x*10;one++){
		for(two=1;two<x*10/2;two++){
			for(five=1;five<x*10/5;five++){
				if(one+two*2+five*5==x*10){
					printf("%d 个1角 + %d 个2角 + %d 个5角 = %d 元\n",one,two,five,x);
				}
			}
		}
	}
		
	return 0;
}

009 求平均数

  • Example 01:
#include <stdio.h>

int main(){
	
	int number;
	int sum = 0;
	int count = 0;
	do{
		scanf("%d",&number);
		
		if(number != -1){
			sum += number;
			count ++;
		}
	}while(number != -1);
	
	printf("%f\n",1.0*sum/count);	
	return 0;
}
  • Example 02:
#include <stdio.h>
 
int main(){
	
	int number;
	int sum = 0;
	int count = 0;
	
	scanf("%d",&number);
		
	while(number != -1){
		sum += number;
		count ++;
		scanf("%d",&number);
	}
	
	printf("%f\n",1.0*sum/count);	
	return 0;
}

010 水仙花数

【题目】计算所有N位水仙花数

【说明】水仙花数是指一个N位正整数(N>=3),它的每个位上的数字的N次幂之和等于它本身。

【输入格式】

输入在一行中给出一个正整数N(3<=N<=7)

【输出格式】

按递增顺序输出所有N位水仙花数,每个数字占一行

【代码】

  • Example 01:
#include <stdio.h>

int main()
{
	int n;
	int first = 1;
	int i = 1;	
	scanf("%d",&n);	
	while(i<n){
		first *= 10;
		i++;
	}
	//遍历100-999
	i = first;
	while(i<first*10){
		int t = i;
		int sum = 0;
		do{
			int d = t%10;
			t /= 10;
			int p = 1;
			int j = 0;
			//int p = d;
			//int j = 1;
			while(j<n){
				p *= d;
				j++;
			}
			sum += p;
		} while(t>0);
		if(sum == i){
			printf("%d\n",i);
		}
		i++;
	} 
    
    return 0;
}

011 打印九九乘法表

  • Example 01:
#include <stdio.h>

int main()
{
	int n;
	scanf("%d",&n); 
	int i,j;
	i=1;
	while(i<=n){
		j=1;
		while(j<=i){
			printf("%d*%d=%d",j,i,i*j);
			if(i*j<10){
				printf("   ");
			}else{
				printf("  ");
			}
			j++;
		}
		printf("\n");
		i++;
	}
    
    return 0;
}

012 统计素数并求和

【题目】要求统计给定整数M和N区间内素数的个数并对它们求和。

【代码】

  • Example 01:
#include <stdio.h>

int main()
{
	int m,n;
	int i;
	int count = 0;
	int sum = 0;
	
	scanf("%d %d",&m,&n); 
	
	if(m==1){
		m=2;
	}
	for(i=m;i<=n;i++){
		int isPrime = 1;
		int k;
		for(k=2;k<i-1;k++){
			if(i%k == 0){
				isPrime = 0;
				break;
			}
		}
		//判断i是否素数
		if(isPrime){
			count++;
			sum += i;
		}		
	}
	
	printf("%d %d\n",count,sum);
	
    return 0;
}
  • Example 02:
#include <stdio.h>

int isPrime(int i){
	int result = 1;
	int k;
	for(k=2;k<i-1;k++){
		if(i%k == 0){
			result = 0;
			break;
		}
	}
	return result;
}

int main(){
	int m,n;
	int i;
	int count = 0;
	int sum = 0;
	
	scanf("%d %d",&m,&n); 
	
	if(m==1){
		m=2;
	}
	for(i=m;i<=n;i++){
		
		//判断i是否素数
		if(isPrime(i)){
			count++;
			sum += i;
		}		
	}
	
	printf("%d %d\n",count,sum);
	
    return 0;
}

013 猜数游戏

【题目】

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RBkfq43c-1583567038702)(https://wugenqiang.github.io/CS-Notes/images/image-20200301210457942.png)]

【代码】

  • Example 01:
#include <stdio.h>

int main()
{
	int number,n;
	int inp;
	int finished = 0;
	int cnt = 0;
	scanf("%d %d",&number,&n);
	do{
		scanf("%d",&inp);
		cnt++;
		if(inp<0){
			printf("Game Over\n");
			finished = 1;
		}else if(inp>number){
			printf("Too big\n");		
		}else if(inp<number){
			printf("Too small\n");
		}else{
			if(cnt==1){
				printf("Bingo!\n");
			} else if(cnt<=3){
				printf("Lucky You!\n");
			}else{
				printf("Good Guess!\n");
			}
			finished = 1;
		} 
		if(cnt==n){
			if(!finished){
				printf("Game Over\n");
				finished = 1;
			}
		}
	} while(!finished);
	
    return 0;
}

014 求序列前N项和

【题目】计算序列2/1+3/2+5/3+8/5+…的前N项之和。

【代码】

  • Example 01:
#include <stdio.h>

int main()
{
	int n;
	double dividend,divisor;
	double sum = 0.0;
	int i;
	double t;
	scanf("%d",&n);
	dividend = 2;
	divisor = 1;
	for(i=1;i<=n;i++){
		sum += dividend/divisor;
		t = dividend;
		dividend += divisor;
		divisor = t;
	} 
	printf("%.2f\n",sum);
	
    return 0;
}

015 约分最简分式

【代码】

  • Example 01:
#include <stdio.h>

int main()
{
	int dividend,divisor;
	scanf("%d/%d",&dividend,&divisor);
	int a = dividend;
	int b = divisor;
	int t;
	while(b>0){
		t = a%b;
		a = b;
		b = t;
	}
	printf("%d/%d\n",dividend/a,divisor/a);
	
    return 0;
}

016 念数字

【题目】输入一个整数,输出每个数字对应的拼音

【代码】

  • Example 01:
#include <stdio.h>

int main()
{
	int x;
	scanf("%d",&x);
	if(x<0){
		printf("fu ");
		x = -x;
	}
	int mask = 1;
	int t = x;
	while(t>9){
		t /= 10;
		mask *= 10;
	}
	do{
		int d = x / mask;
		switch(d){
			case 0: printf("ling");break;
			case 1: printf("yi");break;
			case 2: printf("er");break;
			case 3: printf("san");break;
			case 4: printf("si");break;
			case 5: printf("wu");break;
			case 6: printf("liu");break;
			case 7: printf("qi");break;
			case 8: printf("ba");break;
			case 9: printf("jiu");break;
		}
		if(mask>9){
			printf(" ");
		}
		x %= mask;
		mask /= 10;
	}while(mask>0);
	printf("\n"); 
	
    return 0;
}

017 求a的连续和

【题目】S = a + aa + aaa + … +aaa…a(n个a)

例如:S = 2 + 22 + 222 (3个2)

【代码】

  • Example 01:
#include <stdio.h>

int main()
{
	int a,n;
	scanf("%d %d",&a,&n);
	int sum = 0;
	int i;
	int t = 0;
	for(i=0;i<n;i++){
		t = t*10 + a;
		sum += t;
	} 
	printf("%d\n",sum);
	
    return 0;
}

018 输出平均数和大于平均数的数

【代码】

  • Example 01:
#include <stdio.h>
 
int main(){
	
	int x;
	double sum = 0;
	int count = 0;
	int number[100];	
	scanf("%d",&x);		
	while(x != -1){
		number[count] = x;
		sum += x;
		count ++;
		scanf("%d",&x);
	}
	if(count>0){
		printf("%f\n",sum/count);
		int i;
		for(i=0;i<count;i++){
			if(number[i]>sum/count){
				printf("%d\n",number[i]);
			}
		}
	}
	
	return 0;
}

注:数据超过100时咋办?

  • Plan A:采用动态的下标

  • Plan B:进行说明,if 判断

    019 统计个数

【题目】写一个程序,输入数量不确定的[0,9]范围内的整数,统计每一种数字出现的次数,输入-1表示结束

【代码】

  • Example 01:
#include <stdio.h>
 
int main(){
	
	int x;
	int count[10];
	int i;
	for(i=0;i<10;i++){
		count[i]=0;
	}
	scanf("%d",&x);
	while(x!=-1){
		if(x>=0&&x<=9){
			count[x]++;
		}
		scanf("%d",&x);
	}
	for(i=0;i<10;i++){
		printf("%d:%d\n",i,count[i]);
	}
	
	return 0;
}
  • Example 02:
#include <stdio.h>
 
int main(){
	
	const int number = 10;
	int x;
	int count[number];
	int i;
	for(i=0;i<number;i++){
		count[i]=0;
	}
	scanf("%d",&x);
	while(x!=-1){
		if(x>=0&&x<=9){
			count[x]++;
		}
		scanf("%d",&x);
	}
	for(i=0;i<number;i++){
		printf("%d:%d\n",i,count[i]);
	}
	
	return 0;
}

020 搜索数字

【题目】查找数字是否在数组中,找到返回在数组中的位置,找不到返回-1

【代码】

  • Example 01:使用数组
#include <stdio.h>

int search(int key,int a[],int length);//声明 

int main(){
	
	int a[] = {2,4,6,7,1,3,};
	int x;
	int loc;
	printf("请输入一个数字:");
	scanf("%d",&x);
	loc = search(x,a,sizeof(a)/sizeof(a[0]));
	if(loc != -1){
		printf("%d在第%d个位置上\n",x,loc);
	} else{
		printf("%d不存在\n",x);
	}
	
	return 0;
}

int search(int key,int a[],int length){
	int result = -1;
	int i;
	for(i=0;i<length;i++){
		if(a[i] == key){
			result = i;
			break;
		}
	}
	return result;
} 

021 素数表

【代码】

  • Example 01:
#include <stdio.h>

int main(){
	
	const int maxNumber = 100;
	int isPrime[maxNumber];
	int i;
	int x;
	for(i=0;i<maxNumber;i++){
		isPrime[i] = 1;
	}
	for(x=2;x<maxNumber;x++){
		if(isPrime[x]){
			for(i=2;i*x<maxNumber;i++){
				isPrime[i*x] = 0;
			}
		}
	}
	for(i=2;i<maxNumber;i++){
		if(isPrime[i]){
			printf("%d\t",i);
		}
	}
	printf("\n");
	
	return 0;
}

022 tic-tac-toe游戏

【题目】

  • 读入3×3的矩阵,矩阵中的数字为1表示该位置上有一个X,为0表示一个为O

  • 程序判断这个矩阵中是否有获胜的一方,输出表示获胜一方的字符X或O,或输出无人获胜

【代码】

  • Example 01:
#include <stdio.h>

int main(){
	
	const int size = 3;
	int board[size][size];
	int i,j;
	int numOfX;
	int numOfO;
	int result = -1;//-1:没人赢 1:X赢 0:O赢 
	
	//读入矩阵 
	for(i=0;i<size;i++){
		for(j=0;j<size;j++){
			scanf("%d",&board[i][j]);
		}
	} 
	//检查行
	for(i=0;i<size && result == -1;i++){
		numOfO = numOfX = 0;
		for(j=0;j<size;j++){
			if(board[i][j] == 1){
				numOfX ++;
			}else{
				numOfO ++;
			}
		}
		if(numOfO == size){
			result = 0;
		}else if(numOfX == size){
			result = 1;
		}
	} 
	//检查列 
	if(result == -1){
		for(j=0;j<size && result == -1;j++){
			numOfO = numOfX = 0;
			for(i=0;i<size;i++){
				if(board[i][j] == 1){
					numOfX ++;
				}else{
					numOfO ++;
				}
			}
			if(numOfO == size){
				result = 0;
			}else if(numOfX == size){
				result = 1;
			}
		}
	}
	//检查对角线
    numOfO = numOfX = 0;
    for(i=0;i<size;i++){
		if(board[i][i] == 1){
			numOfX ++;
		}else{
			numOfO ++;
		}
	}
	if(numOfO == size){
		result = 0;
	}else if(numOfX == size){
		result = 1;
	}
	numOfO = numOfX = 0;
	for(i=0;i<size;i++){
		if(board[i][size-i-1] == 1){
			numOfX ++;
		}else{
			numOfO ++;
		}
	}
	 
	return 0;
}

更新笔记地址:EnjoyToShare-C-Notes

查阅更多笔记:EnjoyToShare-CS-Notes


发布了120 篇原创文章 · 获赞 201 · 访问量 23万+

猜你喜欢

转载自blog.csdn.net/wugenqiang/article/details/104715903
今日推荐