初识C语言
C语言中%d,等等%
的用法,和意义 - 知乎 (zhihu.com)
常用语句
1 2 3 4 5 6 7 8 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main () { return 0 ; }
1 2 3 4 5 6 #ifndef __AAD_H__ #define __ADD_H__ int add (int x, int y) ;#endif
数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <stdio.h> int main () { printf ("hello world\n" ); printf ("short占 %lld 个字节\n" , sizeof (short )); printf ("int占 %lld 个字节\n" , sizeof (int )); printf ("long占 %lld 个字节\n" , sizeof (long )); printf ("long long占 %lld 个字节\n" , sizeof (long long )); printf ("float占 %lld 个字节\n" , sizeof (float )); printf ("double占 %lld 个字节\n" , sizeof (double )); printf ("char占 %lld 个字节\n" , sizeof (char )); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <stdio.h> int main () { int a = 0 ; int b = 0 ; int sum = 0 ; scanf_s("%d%d" , &a, &b); sum = a + b; printf ("sum = %d\n" , sum); return 0 ; }
变量、常量
static
静态变量,在函数中再次使用时不会重新定义
1 2 3 4 5 6 7 enum Sex { male, female, }; enum Sex c = female;printf ("c = %d\n" , c);
字符串
1 2 3 4 5 6 7 8 9 10 #include <stdio.h> int main () { char arr1[] = "abc" ; char arr2[] = { 'a' , 'b' , 'c' ,0 }; printf ("arr1 = %s\n" , arr1); printf ("arr2 = %s\n" , arr2); return 0 ; }
操作符
b = a++
与
b = ++a
,第一个是b先等于a,然后a再加2,第二个是a先加2,然后b等于a
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <stdio.h> int main () { int a, b, c; a = 0 ; b = a++; c = ++a; printf ("%d%d%d" , a, b, c); return 0 ; }
exp? exp1 : exp2
三目操作符 exp?
为真则执行 exp1
,为假则执行 exp2
1 2 3 4 5 6 7 8 9 int main () { int a = 5 ; int b = 4 ; int max = a < b ? a + 1 : b - 1 ; printf ("a = %d\n" , max); printf ("max = %d\n" , max); return 0 ; }
关键字
1 2 3 4 5 6 7 8 9 10 11 extern int g_val;extern int add (int , int ) ;int main () { int a = 5 ; int b = 4 ; int res = add(a, b); printf ("res = %d\n" , res); printf ("g_val = %d\n" , g_val); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #define g_val 10; #define max(x, y) (x > y? x : y) extern int add (int , int ) ;typedef unsigned int u_intint main () { int a = 5 ; int b = 9 ; int max = max(a, b); int res = add(a, b); printf ("res = %d\n" , res); printf ("max = %d\n" , max); printf ("g_val = %d\n" , g_val); return 0 ; }
指针
1 2 3 4 5 6 7 8 int main () { int a = 10 ; int * p = &a; *p = 20 ; printf ("%d\n" , 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> struct book { char name[18 ]; short price; }; int main () { struct book b1 = {"法国人" , 16 }; printf ("书名:%s\n" , b1.name); printf ("价格:%d\n" , b1.price); struct book * p = &b1; printf ("书名:%s\n" , (*p).name); printf ("价格:%d\n" , (*p).price); printf ("书名:%s\n" , p -> name); printf ("价格:%d\n" , p ->price); return 0 ; }
分支与循环
顺序语句
again: goto again;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int main () { char str1[] = "hello" ; char str2[] = "hello" ; again: if (strcmp (str1, str2) == 0 ) { printf ("相等\n" ); } else { printf ("不相等\n" ); goto again; } return 0 ; }
选择语句
if语句
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 age; scanf_s("%d" , &age); if (age < 18 ) { printf ("未成年" ); } else if (18 <= age && age < 28 ) { printf ("青年" ); } else if (28 <= age && age < 48 ) { printf ("中年" ); } return 0 ; }
switch语句
case
是入口,break
是出口,没有
break
从符合条件的 case
处开始往下执行,switch
的条件只能是整数常量
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <stdio.h> int main () { int data; printf ("输入一个值:" ); scanf_s("%d" , &data); if (1 <= data && data <= 7 ) { switch (data) { case 1 : printf ("今天是星期一\n" ); break ; case 2 : printf ("今天是星期二\n" ); break ; case 3 : printf ("今天是星期三\n" ); break ; case 4 : printf ("今天是星期四\n" ); break ; case 5 : printf ("今天是星期五\n" ); break ; case 6 : printf ("今天是星期六\n" ); break ; case 7 : printf ("今天是星期天\n" ); break ; default : printf ("请输入正确的数" ); break ; } } else { printf ("请重新输入\n" ); } return 0 ; }
循环语句
for
循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main () { int num1 = 2 ; int num2; int num3 = 1 ; int num4 = 0 ; for (int i = 1 ; i <= num1; i++) { for (int j = 0 ; j < i; j++) { num2 = j + 1 ; num3 = num3 * num2; } num4 = num4 + num3; num3 = 1 ; } printf ("%d\n" , num4); return 0 ; }
while
循环
1 2 3 4 5 6 7 8 9 10 11 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main () { while (i<=10 ) { printf ("hehe\n" ); i = i+1 ; } }
do while
循环
1 2 3 4 5 6 7 8 9 10 11 #include <stdio.h> int main () { int i = 10 ; do { printf ("%d\n" , i); } while (i<10 ); return 0 ; }
continue
退出本次循环
1 2 3 4 5 6 7 8 9 10 11 12 #include <stdio.h> int main () { int i = 0 ; for (i=1 ; i<=10 ; i++) { if (i == 5 ) continue ; printf ("%d " ,i); } return 0 ; }
break
退出循环
1 2 3 4 5 6 7 8 9 10 11 12 #include <stdio.h> int main () { int i = 0 ; for (i=1 ; i<=10 ; i++) { if (i == 5 ) break ; printf ("%d " ,i); } return 0 ; }
函数
定义函数与头文件
通常使用 add.c
与 add.h
来定义函数与头文件,add.c
来存放函数,add.h
来存放函数 函数与变量的声明
定义头文件
1 2 3 4 5 6 #ifndef __AAD_H__ #define __ADD_H__ int add (int x, int y) ;#endif
使用头文件
1 2 3 4 5 6 7 8 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include "add.h" int main () { return 0 ; }
函数的定义与声明
函数定义在主函数后可以不用声明
外部函数与变量用 extern
来声明
1 2 3 extern int g_val;extern int add (int , int ) ;extern int sum (int arr[], int k) ;
函数的调用
传值调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> void swap (int a, int b) { int c; c = *a; *a = *b; *b = c; } int main () { int x, y; x = 4 ; y = 1 ; swap(x, y); printf ("%d %d" , x, y); return 0 ; }
传地址调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> void swap (int * a, int * b) { int c; c = *a; *a = *b; *b = c; } int main () { int x, y; x = 4 ; y = 1 ; swap(x, y); printf ("%d %d" , x, y); return 0 ; }
传递数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int putarr (int arr[], int arr_size) { for (int n = 0 ; n < arr_size; n++) { printf ("%d," , arr[n]); } return 0 ; } int main () { int num[] = {1 , 2 , 3 , 4 }; num_size = sizeof (num) / sizeof (num(0 )); putarr(num, num_size); 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 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int string_len (char * arr) { static int num; if (*arr != '\0' ) { return 1 + string_len(arr + 1 ); } else { return 0 ; } } int main () { char arr[] = "asdf" ; int num_arr = string_len(arr); printf ("%d\n" , num_arr); return 0 ; }
数组
数组相关性质
字符串数组的长度
一维数组的地址是连续的,每次加上对应数据类型的字节,地址由低到高
char
类型的数组,定义方式不同,sizeof()
的结果不同
通过函数传递数组,传递的只是首元素的地址,不能在函数里面通过
sizeof()
来计算元素个数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> int main () { char arr1[] = "12345" ; char arr2[] = { '1' , '2' , '3' , '4' , '5' }; printf ("arr_sizeof: %d\n" , sizeof (arr1)); printf ("arr_strlen: %d\n" , strlen (arr1)); printf ("arr_sizeof: %d\n" , sizeof (arr2)); printf ("arr_strlen: %d\n" , strlen (arr2)); return 0 ; }
数组地址与数组首元素地址 数组 arr
是数组首元素地址,sizeof(arr)
除外
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main () { int arr[] = {1 , 2 , 3 , 4 , 5 , 6 }; printf ("%p\n" , arr); printf ("%p\n" , arr + 1 ); printf ("%p\n" , &arr[0 ]); printf ("%p\n" , &arr[0 ] + 1 ); printf ("%p\n" , &arr); printf ("%p\n" , &arr + 1 ); return 0 ; }
## 二维数组
二维数组的行可以省略,行不可以省略
二维数组的地址是连续的,每次加上对应数据类型的字节
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> int main () { int arr[][3 ] = { {1 , 2 , 3 }, {4 , 5 , 6 } }; for (int i = 0 ; i < 2 ; i++) { for (int j = 0 ; j < 3 ; j++) { printf ("%d " , arr[i][j]); } printf ("\n" ); } return 0 ; }
操作符
运算操作符
>>
只能作用于整数
算术右移 右边丢弃,左边补原来的符号位
逻辑右移 右边丢弃,左边补0
1 2 3 4 5 6 7 8 9 10 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main () { int a = 2 ; int b = a >> 1 ; printf ("%d" , b); return 0 ; }
1 2 3 4 5 6 7 8 9 10 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main () { int a = 2 ; int b = a << 1 ; printf ("%d" , b); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main () { int num, count; count = 0 ; scanf_s("%d" , &num); for (int i = 0 ; i < 32 ; i++) { if (((num >> i) & 1 ) == 1 ) { count++; } } printf ("%d\n" , count); return 0 ; }
|
按位或,只能作用于整数
!
按位非,只能作用于整数
^
按位非,只能作用于整数,相异为1,相同为0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main () { int a = 3 ; int b = 5 ; a = a ^ b; b = b ^ a; a = b ^ a; printf ("%d\n" , a); printf ("%d\n" , b); return 0 ; }
逻辑操作符
&&
逻辑与,
a && b && c
, 若左边为0,
则右边不再运算
1 2 3 4 5 6 7 8 9 10 11 #include <stdio.h> int main () { int i = 0 , a = 0 , b = 2 , c = 3 , d = 4 ; i = a++ && ++b && d++; printf ("a = %d, b = %d, c = %d, d = %d\n" , a, b, c, d); return 0 ; }
- ||
逻辑或,a && b && c
, 若左边为1,
则右边不再运算
1 2 3 4 5 6 7 8 9 10 11 #include <stdio.h> int main () { int i = 0 , a = 0 , b = 2 , c = 3 , d = 4 ; i = a++ || ++b || d++; printf ("a = %d, b = %d, c = %d, d = %d\n" , a, b, c, d); return 0 ; }
符合运算符
+=
a += 1
等价于
a = a + 1
-=
a -= 1
等价于
a = a - 1
单目操作符
只有一个操作数,称为单目操作符
!a
非运算
-a
取反
&a
取地址操作符
*a
解引用操作符,a 为地址找到地址对应的内容
&a
取地址操作符
sizeof(a)
计算a的大小,单位为字节,sizeof()内部不参与运算
1 2 3 4 5 6 7 8 9 10 11 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main () { short s = 0 ; int a = 5 ; printf ("%d\n" , sizeof (s = a + 10 )); printf ("%d\n" , s); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main () { int a = 11 ; a = a | (1 << 2 ); printf ("%d\n" , a); a = a & (~(1 << 2 )); printf ("%d\n" , a); return 0 ; }
++
a++
, 先使用后加加, ++a
先加加后使用
(int)
强制类型转换
条件操作符
exp? exp1 : exp2
, exp?
为1则执行
exp1
, 为0则执行 exp2
1 2 3 4 5 6 7 8 9 10 11 #include <stdio.h> int main () { int a, b; a = 0 ; b = (a > 1 ? 3 : 5 ); printf ("%d\n" , b); return 0 ; }
逗号表达式
a = (exp0, exp1, exp2)
从左到右执行,整个表达式的的结果是最后一个表达式的结果
表达式求值
隐式表达式
字符和短整型操作数在运算前会进行整型提升,即将其转换为普通整形,再进行运算。整型提升是将其首位扩充到整形的4字节
1 2 3 4 5 6 7 8 9 10 11 12 #include <stdio.h> int main () { char a, b, c; a = 127 ; b = 3 ; c = a + b; printf ("%d\n" , c); return 0 ; }
运算过程
a = 01111111, 整型提升: a = 00000000 00000000 00000000 01111111
b = 0000011, 整型提升: b = 00000000 00000000 00000000 0000011
c = a + b = 00000000 00000000 00000000 1000010 = 10000010
打印时进行运算c = 1000010,整型提升: c = 11111111 11111111 11111111
10000010(补码)
c = 11111111 11111111 11111111 10000001(反码)
c = 10000000 00000000 00000000 01111110(原码)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <stdio.h> int main () { char a = 0xb6 ; short b = 0xb600 ; int c = 0xb6000000 ; if (a == 0xb6 ) printf ("a" ); if (b == 0xb600 ) printf ("b" ); if (c == 0xb6000000 ) printf ("c" ); return 0 ; }
1 2 3 4 5 6 7 8 9 10 #include <stdio.h> int main () { char c = 1 ; printf ("%u\n" , sizeof (c)); printf ("%u\n" , sizeof (+c)); printf ("%u\n" , sizeof (!c)); return 0 ; }
运算优先级
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <stdio.h> int main () { float values[5 ]; float *vp; for (vp = &values[0 ]; vp < values[5 ]) { *vp++ = 0 ; } return 0 ; }
# 指针
指针+/- 指针为元素的个数
const int* p = &n
表示 *p
不能被修改,
int* const p = &n
表示 p
不能被修改
1 2 3 4 5 6 7 8 9 10 11 #include <stdio.h> int main () { int n, m = 1 , 2 ; const int * p = &n; int * const pa = &n; *p = 2 ; pa = &m; return 0 ; }
指针的类型
指针大小都是4/8个字节
指针类型决定了解引用对应内存大小,以及指针+1对应地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <stdio.h> int main () { int n = 1 ; int * pa = &n; char * pb = &n; printf ("%p\n" , pa); printf ("%p\n" , pa + 1 ); printf ("%p\n" , pb); printf ("%p\n" , pb + 1 ); return 0 ; }
## 野指针
定义
野指针成因
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <stdio.h> #include <stdio.h> int main () { int arr[10 ] = { 0 }; int * p = arr; int i = 0 ; for (i = 0 ; i <= 11 ; i++) { *(p++) = i; } return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int * text () { int a = 10 ; return &a; } int main () { int * p = text(); *p = 20 ; return 0 ; }
指针运算
指针 +/- 整数
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <stdio.h> int main () { float values[5 ]; float *vp; for (vp = &values[0 ]; vp < values[5 ]) { *vp++ = 0 ; } return 0 ; }
指针 - 指针
1 2 3 4 5 6 7 8 9 10 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main () { int values[5 ] = { 0 , 1 , 2 , 3 , 4 }; int num_values = &values[4 ] - &values[0 ]; printf ("%d" , num_values); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int my_strlen (char * str) { char * start = str; char * end = str; int count = 0 ; while (*end != '\0' ) { end++; } return end - start; } int main () { char arr[] = "123456" ; int num_arr = my_strlen(arr); printf ("%d" , num_arr); return 0 ; }
指针的关系运算
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <stdio.h> int main () { float values[5 ]; float *vp; for (vp = &values[5 ]; vp > values[0 ]) { *--vp = 0 ; } return 0 ; }
指针与数组
数组名 arr
是数组首元素地址,有两个例外
&arr
是数组全部数组元素地址
sizeof(arr)
是整个数组的大小
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main () { int arr[10 ] = { 0 }; printf ("%p\n" , arr); printf ("%p\n" , &arr[0 ]); printf ("%p\n" , &arr); printf ("%p\n" , arr + 1 ); printf ("%p\n" , &arr + 1 ); return 0 ; }
## 二级指针
1 2 3 4 5 6 7 8 9 10 11 12 13 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main () { int a = 1 ; int * pa = &a; int ** ppa = &pa; printf ("%d\n" , a); printf ("%d\n" , *pa); printf ("%d\n" , **ppa); return 0 ; }
指针数组
int* arr[] = {&a, &b, &b}
存放指针的数组
1 2 3 4 5 6 7 8 9 10 11 12 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main () { int a = 1 , b = 2 , c = 3 ; int * arr[] = {&a, &b, &b}; printf ("%p == %p\n" , &a, &arr[0 ]); for (int i = 0 ; i < 3 ; i++) printf ("%d\n" , *arr[i]); 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 27 28 29 30 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> struct stu { char name[20 ]; short age; char tele[12 ]; char sex[5 ]; }stu1, stu2, stu3; typedef struct student { char name[20 ]; short age; char tele[12 ]; char sex[5 ]; }student; int main () { struct stu stu_001 = {"小红" , 15 , "xxx" , "x" }; student stu_002 = { "小红" , 15 , "xxx" , "x" }; 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 27 28 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> struct s { char name[20 ]; short age; char tele[12 ]; char sex[5 ]; }; struct t { char ch[20 ]; struct s s ; char *pc; }; int main () { char arr[] = "hello world" ; struct t stu = { "小红" , {"小白" , 15 , "123456789001" , "x" }, arr}; printf ("%s\n" , stu.ch); printf ("%s\n" , stu.s.name); 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 27 28 29 30 31 32 33 34 35 36 37 38 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> struct stu { char name[20 ]; short age; char tele[12 ]; char sex[5 ]; }; void ptint_struct (struct stu tmp) { printf ("%s\n" , tmp.name); printf ("%d\n" , tmp.age); printf ("%s\n" , tmp.tele); printf ("%s\n" , tmp.sex); } void ptint2_struct (struct stu* tmp) { printf ("%s\n" , tmp -> name); printf ("%d\n" , tmp -> age); printf ("%s\n" , tmp -> tele); printf ("%s\n" , tmp -> sex); } int main () { struct stu stu_001 = { "小白" , 15 , "123456789001" , "x" }; ptint1_struct(stu_001); ptint2_struct(&stu_001); return 0 ; }