- 字面常量: 直观写出来的值
- const修饰发常量
- #define定义的常量
- 枚举常量
int main()
{
const int num = 1;\const 表示常属性变量的创建
num = 8;
return 0;
}
是不能运行的
int main()
{
const int n = 4;
printf("%dn", n);
int arr[n] = { 0 };
return 0;
}
int main()
{
const const int n = 4;
printf("%dn", n);
int arr[n] = { 0 };
return 0;
}
都不能运行, const int n表示n是一个具有常属性的变量,不是常量.
#define _CRT_SECURE_NO_WARNINGS 1 #include#define MAX 10 int main() { int arr[MAX] = { 0 }; return 0; }
这个可以运行,因为#define定义了一个标准常量
枚举常量enum Sex\枚举常量
{
MALE,
FEMALE,
SECRET
};//枚举常量的可能取值, 大括号内给定的枚举常量是不能改变的, 枚举变量是可以改变的
int main()
{
printf("%d",MALE);//0
printf("%d",FEMALE);//1
printf("%d",SECRET);//2
}
字符串+转义字符+注释
字符串
多个字符放在双引号内就是字符串 "hello bitn"
int main()
{
"abcdef";//字符串
"";//空字符串
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1 #includeint main() { char arr1[] = "abc"; //"abc"--'a','b','c',' ' =>' '表示字符串的结束标志,' '的值是0 //char arr2[] = { 'a','b','c' };'c'的后面应该加上一个0 char arr2[]={'a','b','c',0}; printf("%sn", arr1); printf("%sn", arr2); printf("%dn", strlen(arr1)); printf("%dn", strlen(arr2));//打印字符串长度,3 return 0; }
数据在计算机上存储的是二进制,字符是以ASCII编码储存.
转义字符n把本义变了,使某一个字符不再是原来的意思,表示换行
#define _CRT_SECURE_NO_WARNINGS 1 #includeint main() { printf("abcn"); return 0; }
t叫水平制表符,类似Tab键
注释c的注释 c++的注释//` 都可以用 注释用于代码难懂的地方
输入输出 格式字符| 格式符号 | 作用 |
|---|---|
| i, d | 十进制整数 |
| x, X | 十六进制无符号整数 |
| o | 八进制无符号整数 |
| u | 无符号十进制整数 |
| c | 单一字符 |
| s | 字符串 |
| e | 指数形式浮点小数 |
| f | 小数形式浮点小数 |
#includeint main() { float f=3.1415926; printf("%2.3fn",f); printf("%fn",f); return 0; }
其中%2.3f2表示格式(被超过了就忽略), 3表示保留小数点位数(四舍五入)
| 修饰符 | 功能 |
| m | 输出数据域宽,数据长度 |
| .n | 对实数,指定小数点后位数(四舍五入) |
| 对字符串,指定实际输出位数 | |
| - | 输出数据在域内左对齐(缺省右对齐) |
| + | 指定在有符号数的正数前显示正号(+) |
| 0 | 输出数值时指定左面不使用的空位置自动填0 |
| # | 在八进制和十六进制数前显示前导0,0x |
| l | 在d, o, x, u前,指定输出精度为long型 |
| l | 在e, f, g前,指定输出精度为double型 |
putchar()
scanf() 如果需要提示语句, 单独写一行printf, 不能写在scanf中
输入函数留下的垃圾即输入一个整型值后紧接着按回车输入另一个字符, 会将回车变成输入. 清除的方法有
1. 用getchar()吃掉 1. %[空格]c或%*c字符串输入函数
- gets(s)
- scanf()会将空格作为字符串输入的结束标志(处理连续字符输入时可以处理空格)
puts
会自动换行
运算符 算数运算符加 减 乘 除(/) 取余(%) 取余不能给浮点数进行.
关系运算符>``>=``<=``<
==``!=
逻辑运算符- !取反: 1变 0,0变1
- ||或
针对二进制的位(0/1)
位运算可以以任何数据类型
| 运算符 | 功能说明 | |
|---|---|---|
| ~ | 位逻辑反 | 转换为二进制, 然后0 1 互换 |
| & | 位逻辑与 | |
| | | 位逻辑或 | |
| ^ | 位逻辑亦或 | 相异为真, 相同为假 |
| >> | 右移位 | |
| << | 左移位 | 乘二 |
条件运算符? 逗号运算符
z=(x+=5,y=x+0.2)
z的值由最后一个表达式决定
运算符的优先级建议多加括号解决优先级问题
#include补充int main() { int x = 1, y = 0, z = 0; x += y == z,y = x + 2, z = x + y + x > 0; printf("%d,%d,%dn", x, y, z); return 0; }
解引用运算符*的优先级要小于下标运算符[], 因此表示数组指针需要加括号例如int (*p)[10]
数组 一维数组C语言中不会对数组做越界判断, 需要自己限制
- 数组如果不初始化, 值是随机的.
- static数组元素不赋值, 默认是0
- 只给部分赋值, 后面默认0
- 初始化给多了直接报错
#include二维数组int main(int argc, char const *argv[]) { int a[7]={49,38,97,76,13,27,30}; int i = 0,j=6,temp; for (;j>=0;j--) { for(i=0;i<=j;i++) { if(a[i]>a[i+1]) { temp = a[i]; a[i] = a[i+1]; a[i+1] = temp; } } } for(i=0;i<=6;i++) { printf("%dn",a[i]); } return 0; }
P[行][列]
定义方式: 行数可以省略, 列数不可以
二维数组的存储二维数组存储的验证
#include多维数组 例题: 打印杨辉三角的前十行int main(int argc, char const *argv[]) { int a[4][5]={{1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15},{16,17,18,19,20}}; for(int x = 0; x < 4; x++) { for(int y = 0; y < 5; y++) { printf("The id of a[%d][%d] is %pn",x,y,&a[x][y] ); } } return 0; }
#include字符数组和字符串int main(int argc, char const *argv[]) { int a[10][10]; for(int x = 0; x < 10; x++) { for(int y = 0; y < 10; y++) { if(y == 0 ||x == y) a[x][y]=1; } } for(int x = 2; x < 10; x++) { for(int y = 1; y < x; y++) { a[x][y]=a[x-1][y-1]+a[x-1][y]; } } for(int x = 0; x < 10; x++) { for(int y = 0; y <= x; y++) { printf("%d ",a[x][y]); } printf("n"); } return 0; }
C语言中, 字符串依附于字符数组存在
初始化- 逐个元素赋值
- 字符串赋值 "abc" ->a, b, c,
0 NULL都是一回事, ASCII码值是0
, '0'是另一回事, ASCII码值是48
二维数组下的字符串数组#includeint main() { char fruit[][20] = { "bannana","apple","strawmerry","watermelen" }; int i, j, n, m; n = sizeof(fruit) / sizeof(fruit[0]); m = sizeof(fruit[0]) / sizeof(fruit[0][0]); for (i = 0; i < n; i++) { for (j = 0; j < m; j++) { putchar(fruit[i][j]); } putchar('n'); } return 0; }
字符串函数 常见字符串函数sizeof()得到的是总空间, 包括未赋值部分, strlen得到的是实际的字符串长度(需要string.h>)
计算一个字符串的实际长度(不包含 ), 返回的是字节数, 往往一个char就是一个字节, 因此可以视为长度
char s[10] = { 'A', 0, 'b', ' ', '0' };
printf("%zd", strlen(s));//这将返回1, 因为遇到0, 就认为字符串结束了
printf("%d", sizeof(s)/sizeof(char));//这将返回10, 表示整个数组
遇到特殊字符时:
char s[20] = "ttnasdczx0 qwe";
printf("%zdn", strlen(s));//返回10 t,n分别被视为一个字符
printf("%d", sizeof(s)/sizeof(char));//返回20
char s[20] = "x69141n"; // xhh表示十六进制数代表的符号, ddd表示八进制数代表的符号 一般不建议这样写
printf("%zdn", strlen(s));
strcpy字符串拷贝
- strcpy(字符数组1,字符数组2)
- 将字符串2拷贝到字符串1中去, 返回字符数组1的首地址.(必须是字符串)
- 字符数组1必须足够大
- strcpy(字符数组1,字符数组2)
- 将字符串2连接到字符串1后面, 返回字符数组1的首地址.(必须是字符串)
- 字符数组1必须足够大
- 连接之前,二者都是以' '结束的, 连接后 串1的' 取消,新串最后加' '
strcmp(字符串1,字符串2)
- 比较规则: 两个字符串从左到右依次比较ASCII码值, 若1<2 返回负整数, 若1==2返回0, 若1>2返回正整数.
- 如果长度不等, 空的位置相当于和 比 ,
#include#include int main(int argc, char const* argv[]) { char s1[]="123aeqw$asdsa"; int ch; ch='$'; printf("%p,%p,nn",s1,strchr(s1,ch)); return 0; }
strstr(p, p1) 查找字符串
#include关于字符的函数, 需要#include#include int main(int argc, char const* argv[]) { char s1[]="how are you"; char s2[]="are"; printf("%ldn",strstr(s1,s2)-s1); return 0; }
在C语言中, 内存单元的地址叫指针. 在不影响理解的情况下, 地址, 指针, 指针变量不做区分.
指针运算- 只限于指向相同类型的指针
- 指针相减得到的是所隔数据的个数, 不是地址差.
可以将地址赋值给指针.
解引用*运算符给出指针指向地址上的存储的值
取址和所有变量一样,指针变量也有自己的地址和值. &运算符给出指针本身的地址.
指针与整数相加整数都会和指针指向类型的大小相乘, 再把结果与初始地址相加.
递增指针递增指向数组元素的指针可以让该指针移动到数组的下一个元素. 因此ptr1指向urn[1].
指针减去一个整数指针必须是被减数. 其余与加法类似.
递减指针类似递增, 用于数组
指针求差 指针与数组数组名是指向数组第一个元素的指针.
二维数组中的指针int a[3][2]={{1,6},{9,12},{61,12}};
int *p,i,n;
n=sizeof(a)/sizeof(int);
p=a;//warning
这样写是不对的, a与p类型是有区别的, 一个p指向四个字节, 但是一个a指向8个字节, 应该这样:
p=a[0]
也就是说 如果需要用一级指针遍历二维数组, 需要for循环
二维数组由多个数组构成,
上述代码中a就是由a[0] a[1] a[2] 三个数组构成.
对二维数组名进行一次解引用将得到指向一行数的指针.
字符指针与字符串如果直接让指针指向字符串
char *p="hello world";
指针存储了字符串常量的起始地址, 不能用指针修改 指向对象的值了. 对于数组则不能这样做, 这也是字符串与字符数组的区别.
指针数组若干个存储类型相同的指针变量构成的数组.
double *pa[2], a[2][3]
*只管一个
指针数组可以用于对二维数组.
多级指针 void指针
void * [指针名]
可以通过强制类型转换变为其他类型的指针
显示转换 隐式转换显式调用是指在代码中调用 隐式调用是编译器后台调用
函数 定义和用法l函数是一个完成特定功能的代码模块,其程序代码独立,通常要求有返回值,也可以是空值。大括号内称为函数体
l一般形式如下:
<数据类型> <函数名称>( <形式参数说明> ) {
语句序列;
return[(<表达式>)];
}
例如
double p(int x);调用
函数名(实际参数)
实参就是在使用函数时,调用函数传递给被调用函数的数据。需要确切的数据
函数调用可以作为一个运算量出现在表达式中,也可以单独形成一个语句。对于无返回值的函数来讲,只能形成一个函数调用语句。
参数传递 (C语言没有引用)传递数组参数(非字符串)需要同时传递数组的大小.
复制传递方式实参的值赋值给形参
- 调用函数将实参传递给被调用函数,被调用函数将创建同类型的形参并用实参初始化
- 形参是新开辟的存储空间,因此,在函数中改变形参的值,不会影响到实参
指针函数是一个返回值为指针的函数.
函数中的空间会在结束时释放, 这造成指针无法再访问, 可以将函数内变量申请为static变量延长试用期.
或使用 字符串常量:
char *str = "hello"
但是不能修改*str
总的来说, 指针函数的返回可以是:
- 全局变量的地址
- static变量的地址
- 字符串常量的地址
- 动态内存
例子1: 求阶乘
#includeint calcu(int x); int main() { printf("%dn",calcu(10)); return 0; } int calcu(int x) { if (x==0) { return 1; } double factorial = x; factorial*=calcu(x-1); return factorial; }
例子2: 斐波拉契数列
int main()
{
for(int num = 1; num <= 10; num++)
{
printf("%dn",fib(num));
}
return 0;
}
int fib(int x)
{
int fibx;
if (x == 1 || x == 2)
{
return 1;
}
fibx = fib(x-1)+fib(x-2);
return fibx;
}
函数指针
函数指针的核心是一个指针, 存储函数的地址
函数地址代表了函数的入口地址( 函数名)
#includeint add(int, int); int main() { int m = 10,n = 20; int (*p)(int ,int ); p=add; printf("%dn",p(m,n)); return 0; } int add(int x,int y) { return x+y; }
函数指针要与函数产生关系, 因此需要返回值类型和参数列表和函数的原型一致, 这里注意解引用 *的优先级, 需要加()
函数指针数组数组中函数指针指向函数的返回类型和参数列表一致.
例子: 调用qsort进行排序#include资源&更深入的阅读资料: 领取资料的神秘通道开启点击链接加入群聊【C语言/C++编程学习基地】:828339809#include int stol(const void *x, const void *y); int main() { int a[10] = {5.7,3,6,4,2,8,9,1}; qsort(a,sizeof(a)/sizeof(int),sizeof(int),stol); for(int k = 0; k<= 9; k++) { printf("%dn",a[k] ); } return 0; } int stol(const void *x, const void *y) { return *(int *)x - *(int *)y; }



