最经典的程序

1
2
3
4
5
6
7
#include <stdio.h>
int main()
{
printf("Hello World!\n");

return 0;
}

简陋的”计算程序“

1
2
3
4
5
6
#include <stdio.h>
int main()
{
printf("23+43=%d\n", 23+43);
return 0;
}

注意%d和scanf的用法:

1
2
3
4
5
6
7
8
9
#include <stdio.h>
int main()
{ int a;
int b;
printf("请输入两个整数:");
scanf("%d %d", &a, &b);
printf("%d + %d = %d\n", a, b, a + b);
return 0;
}

定义常量:

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int main()
{ const int AMOUNT =
100;
int price = 0;
printf("请输入金额(元):");
scanf("%d", &price);
int change = AMOUNT - price;
printf("找您%d元。\n", change);
return 0;
}

数据类型:

  • %d:整数

  • %f:浮点数

    抽象的复杂运算式:a = b += c++ - d + --e / -f

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include<stdio.h>
    int main()
    {
    int a,b,c,d,e,f;
    a = 1;
    b = 2;
    c = 3;
    d = 4;
    e = 5;
    f = 6;
    a = b+=c++-d+--e/-f;
    printf("%d",a);
    return 0;
    }

    运算符优先级从高到低:

  1. 后缀递增/递减++--(后缀)
  2. 一元运算符-(负号)、++--(前缀)
  3. 算术运算符*/%
  4. 算术运算符+-
  5. 赋值运算符=+=-=

关系运算

  • 相等==
  • 不相等!=
  • 大于>
  • 大于或者等于>=
  • 小于<
  • 小于或者等于<=

关系运算的结果有两种:1(关系成立)或0(关系不成立),所有的关系运算符都比算术运算符低,比赋值运算符高,判断是否相等或不相等的运算符比其他关系运算符的优先级更低,

逻辑运算

  • !逻辑非
  • &&逻辑与||逻辑或
  • 优先级:!>&&>||

逻辑运算是从左向右的,比如&&,如果左边的结果为false,那就不会再进行右边的计算了;对于||,如果左边的结果是true就不再做右边的运算了,这情况叫做短路

不要把赋值、复合赋值写进表达式,不要写出下面的表达式:

1
2
a==6&&b==1;
a==6&&b+=1;

提醒:单目运算符的优先级高于双目运算符

1
!age<20

上面这个表达式的值永远为1

运算符小结

优先级 运算符 结合性
1 () 从左到右
2 ! + - ++ -- 从右到左(单目的+和-)
3 * / % 从左到右
4 + - 从左到右
5 < <= > >= 从左到右
6 == != 从左到右
7 && 从左到右
8 `
9 = += -= *= /= %= 从右到左

条件运算符

这是一个历史遗留的产物。

count = (count > 20) ? count - 10 : count + 10等价于:

1
2
3
4
5
if (count >20 ) {
count = count -10;
} else {
count = coutn +10;
}

尽可能不要使用嵌套的条件表达式

逗号运算符

逗号用来连接两个表达式,并以右边的表达式的值作为它的结果。

逗号表达式主要是在for循环中使用,比如:

1
for (i=0,j=10;i<j;i++,j--)

第二周作业

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>
int main()
{
int n;
printf("请输入一个正三位数:\n");
scanf("%d",&n);
int a = n/100;
int c = n%10;
int b = (n - 100*a - c)/10;
int m = 100*c+10*b+a;
printf("逆序数字是:%d\n",m);
return 0;
}

改进如下:

  • 获得百位:n/100

  • 获得十位:(n/10)%10

  • 获得个位:n%10

补充更好的做法(不论这个整数 是几位数):

  • 获得千位:(n/1000)%10
  • 获得万位:(n/10000)%10

基本套路

比较大小

1
2
3
4
5
6
7
8
9
10
int a,b;
printf("请输入两个整数:");
scanf("%d %d",&a,&b);
int max=0;
if (a>b){
max=a;
} else{
max=b;
}
printf("大的那个是%d\n",max);
1
2
3
4
5
6
7
8
int a,b;
printf("请输入两个整数:");
scanf("%d %d",&a,&b);
int max=b;
if (a>b){
max=a;
}
printf("大的那个是%d\n",max);

阶乘

1
2
3
4
5
6
7
8
int n;
scanf("%d",&n);
int fact=1;
int i=1;
for (i=1;i<=n;i++){
fact *=1;
}
printf("%d!=%d\n",n,fact);

printf的补0功能

1
2
3
4
5
6
7
8
9
#include <stdio.h>

int main()
{
int mm,dd,yyyy;
scanf("%d-%d-%d",&mm,&dd,&yyyy);
printf("%d-%02d-%02d",yyyy,mm,dd);
c return 0;
}

大于小于数学关系

1
x>4&&x<6

判断字符是否为大小写字符

1
c>='A'&&c<='Z'

保存原始的变量值

1
2
3
4
5
6
7
8
9
int x;
int ret = 0;
scanf("%d",&x);
int t=x;
while (x>1){
x/=2;
ret ++;
}
printf("log2 of %d is %d.",t,ret);

四舍五入(无函数、类型转换)

1
2
3
4
5
int result;
float x = 3.6;

result = x + 0.5; // 不做类型转换,C 会自动截断
printf("%d\n", result); // 输出 4

因为result是整数类型,所以加法会强制截断小数部分

判断奇偶

1
2
3
4
5
int x = 7;
if (x % 2 == 0)
printf("偶数\n");
else
printf("奇数\n");

计算月份的天数(使用数组,未完成)

四则运算计算器(未完成)

素数的判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<stdio.h>
int main(void)
{
int x;
scanf("%d",&x);

int i;
int isPrime=1;
for (i=2;i<x;i++) {
if (x%i==0) {
isPrime=0;
break;
}
}
if (isPrime==1) {
printf("是素数\n");
} else {
printf("不是素数\n");
}
return 0;
}

列举前50个素数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<stdio.h>
int main(void)
{
int x;
x=2;
int cnt=0;

while (cnt<50) {
int i;
int isPrime=1;
for (i=2;i<x;i++) {
if (x%i==0) {
isPrime=0;
break;
}
}
if (isPrime==1) {
printf("%d ",x);
cnt++;
}
x++;
}
printf("\n");
return 0;
}

枚举以零凑整

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<stdio.h>
int main(void)
{
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 %d %d %d\n",one,two,five,x);
}
}
}
}


return 0;
}

交替正负符号的控制

1
2
3
4
for (i=1;i<=n;i++) {
sum+=sign*1.0/i;
sign=-sign;
}

最大公约数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<stdio.h>
int main(void)
{
int a,b;
int min;
scanf("%d %d",&a,&b);
if (a<b) {
min=a;
} else {
min=b;
}
int ret=0;
int i;
for (i=1;i<min;i++) {
if (a%i==0) {
if (b%i==0) {
ret=i;
}
}
}
printf("%d %d is %d\n",a,b,ret);

return 0;
}

辗转相除法求最大公约数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>
int main(void)
{
int a,b;
scanf("%d %d",&a,&b);
while (b!=0) {
t=a%b;
a=b;
b=t;
}
printf("%d is the GCD",a);


return 0;
}

斐波那契数列变种——动态规划问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>

int main() {
int N;
scanf("%d", &N); // 输入目标兔子数量

int month = 0; // 月数
int a = 1, b = 1, c = 0; // a 是第1个月的兔子数量,b 是第2个月的兔子数量,c 是第3个月的兔子数量

while (c < N) {
c = a + b; // 第3个月的兔子数量等于前两个月的兔子数量之和
a = b; // 更新第1个月的兔子数量为第2个月的兔子数量
b = c; // 更新第2个月的兔子数量为第3个月的兔子数量
month++; // 月数增加
}

printf("%d\n", month + 2); // 输出需要的月数(+2是因为初始的两个月)

return 0;
}

计算平均数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<stdio.h> 
int main(void) {
int x;
double sum=0;
int cnt=0;
scanf("%d",&x);
while (x!=-1) {
sum +=x;
cnt++;
scanf("%d",&x);
}
if (cnt>0) {
printf("%f\n",sum/cnt);
}


return 0;
}

使用数组计算平均数并输出大于平均数的所有数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include<stdio.h> 
int main(void) {
int x;
double sum=0;
int cnt=0;
int number[100];
scanf("%d",&x);
while (x!=-1) {
number[cnt]=x;
sum +=x;
cnt++;
scanf("%d",&x);
}
if (cnt>0) {
printf("%f\n",sum/cnt);
int i;
for (i=0;i<cnt;i++) {
if (number[i]>sum/cnt) {
printf("%d\n",number[i]);
}
}
}


return 0;
}

这个程序有点bug,因为用户输入的数目可能超过100,此时数组越界。

统计数字出现的次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<stdio.h>
int main(void) {
const int number=10;
int x;
int count[number];
int i;
for (i=0;i<number;i++) { //所有元素初始化为0,这样每个数字的初始出现次数都是0
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;
}

判断是否为素数的函数

1
2
3
4
5
6
7
8
9
10
11
int isPrime(int i) {
int ret=1;
int k;
for (k=2;k<i-1;k++) {
if (i%k==0) {
ret=0;
break;
}
}
return ret;

改进一下算法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int isPrime(int x) {
int ret = 1;
int i;
if ( x == 1 || (x%2 == 0 && x != 2 )) {
ret = 0;
}
for (i = 3; i <= sqrt(x); i+=2) {
if (x % i == 0 ) {
ret = 0;
break;
}
}
return ret;
}

Sieve of Eratosthenes判断素数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
int main() {
const int maxNumber = 25;
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;
}

求和函数

1
2
3
4
5
6
7
8
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);
}

判断整数位数的函数

1
2
3
4
5
6
7
8
9
10
11
12
int countdigit(int n) {
int i=0;
if (n!=0) {
while (abs(n)>=1) {
n/=10;
i++;
}
} else {
i=1;
}
return i;
}

线性搜索函数

1
2
3
4
5
6
7
8
9
10
11
12
int search{int key; int a[]; int length}
{
int ret = -1;
int i;
for ( i=0; i<length; i++) {
if ( a[i] == key ) {
ret = i;
break;
}
}
return ret;
}

二分搜索函数

1

冒泡排序函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void bubble_sort(int arr[], int len) {
for (int i = 0; i < len - 1; i++) {
int swapped = 0;
for (int j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = 1;
}
}
if (swapped == 0) {
break;
}
}
}

求交错序列前N项和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
int main() {
int sign = 1;
int n;
scanf("%d",&n);
double i;
double sum = 0;
for (i=1; i<n+1; i++) {
sum += sign*(i)/(2*i-1);
sign = -1 * sign;
}
printf("%.3f",sum);
return 0;
}

第二章

变量的命名可以用小写字母、大写字母、数字和下划线,但是操作系统和C库经常使用以一个或两个下划线字符开始的标识符,比如_kcab,因此最好bibi面在自己的程序中使用这种名称。C语言的名称区分大小写

第三章:数据和C

getchar()

getchar()可以读取一个字符:

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int main(void)
{
char c;
printf("please input character:");
c = getchar();
printf("the character is:");
putchar(c);

return 0;
}

数据类型关键字

  • 最初K&R给出:
    • int
    • long
    • short
    • unsigned
    • char
    • float
    • double
  • C90加入:
    • signed
    • void
  • C99加入
    • _Bool
    • _Complex
    • _Imaginary

浮点数

浮点数与数学中实数的概念类似,在一个值后面加上一个小数点,该值就成为一个浮点值,如2.75、3.16E7、7.00、2e-8等。

计算机把浮点数分成小数部分和指数部分来表示,而且分开存这两部分。

  • 对于一些算术运算,浮点数损失的精度更多。

C语言基本数据类型

int

储存一个int要占用一个机器字长,ISO C规定int的取值范围是-32768~32767,在我的64位计算机中则是-2147483648 ~2147483647,可有下代码检验:

1
2
3
4
5
6
7
8
#include <stdio.h>
#include <limits.h>

int main() {
printf("int µÄ×îСֵ£º%d\n", INT_MIN);
printf("int µÄ×î´óÖµ£º%d\n", INT_MAX);
return 0;
}

%d成为转换说明,它指定了printf()应该使用什么格式来显示一个值,格式化字符串的每个%d都与待打印的变量列表中相应的int值匹配,需要注意的是编译器不会捕获这些(转换说明的数量与待打印值的数量不相同)类型的错误

提及二进制、十六进制等一般说的是整型int,它的转换说明有多种:

  • %o以八进制显示
  • %x以十六进制显示

char

C语言把1字节定义为char类型占用的位数,从技术层面看,char是整数类型。

声明char类型变量:char response

字符串常量初始化:char grade = 'A' 不可写成双引号,双引号时代表字符串。

填坑

各种排序算法