当前位置:网站首页>C语言学习笔记
C语言学习笔记
2022-07-06 09:25:00 【编程小鱼六六六】
数据
常量
大分类
- 字面常量: 直观写出来的值
const
修饰发常量#define
定义的常量- 枚举常量
常量,const
常变量
int main()
{
const int num = 1;\\const 表示常属性变量的创建
num = 8;
return 0;
}
是不能运行的
int main()
{
const int n = 4;
printf("%d\n", n);
int arr[n] = { 0 };
return 0;
}
int main()
{
const const int n = 4;
printf("%d\n", n);
int arr[n] = { 0 };
return 0;
}
都不能运行, const int n
表示n是一个具有常属性的变量,不是常量.
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#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 bit\n"
int main()
{
"abcdef";//字符串
"";//空字符串
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
char arr1[] = "abc";
//"abc"--'a','b','c','\0' =>'\0'表示字符串的结束标志,'\0'的值是0
//char arr2[] = { 'a','b','c' };'c'的后面应该加上一个0
char arr2[]={'a','b','c',0};
printf("%s\n", arr1);
printf("%s\n", arr2);
printf("%d\n", strlen(arr1));
printf("%d\n", strlen(arr2));//打印字符串长度,3
return 0;
}
数据在计算机上存储的是二进制,字符是以ASCII编码储存.
转义字符\
\n
把本义变了,使某一个字符不再是原来的意思,表示换行
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
printf("abc\n");
return 0;
}
\t
叫水平制表符,类似Tab键
注释
c的注释/* */ c++的注释
//` 都可以用 注释用于代码难懂的地方
输入输出
格式字符
格式符号 | 作用 |
---|---|
i, d | 十进制整数 |
x, X | 十六进制无符号整数 |
o | 八进制无符号整数 |
u | 无符号十进制整数 |
c | 单一字符 |
s | 字符串 |
e | 指数形式浮点小数 |
f | 小数形式浮点小数 |
#include<stdio.h>
int main()
{
float f=3.1415926;
printf("%2.3f\n",f);
printf("%f\n",f);
return 0;
}
其中%2.3f
2表示格式(被超过了就忽略), 3表示保留小数点位数(四舍五入)
修饰符 | 功能 |
m | 输出数据域宽,数据长度<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<stdio.h>
int main()
{
int x = 1, y = 0, z = 0;
x += y == z,y = x + 2, z = x + y + x > 0;
printf("%d,%d,%d\n", x, y, z);
return 0;
}
补充
解引用运算符*
的优先级要小于下标运算符[]
, 因此表示数组指针需要加括号例如int (*p)[10]
数组
一维数组
C语言中不会对数组做越界判断, 需要自己限制
- 数组如果不初始化, 值是随机的.
- static数组元素不赋值, 默认是0
- 只给部分赋值, 后面默认0
- 初始化给多了直接报错
例题: 冒泡排序
#include<stdio.h>
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("%d\n",a[i]);
}
return 0;
}
二维数组
P[行][列]
定义方式: 行数可以省略, 列数不可以
二维数组的存储
二维数组存储的验证
#include<stdio.h>
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 %p\n",x,y,&a[x][y] );
}
}
return 0;
}
多维数组
例题: 打印杨辉三角的前十行
#include<stdio.h>
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
0 \0 NULL都是一回事, ASCII码值是0
, '0'是另一回事, ASCII码值是48
二维数组下的字符串数组
#include<stdio.h>
int 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>
)
字符串函数
常见字符串函数 <string.h>
strlen
求长度
计算一个字符串的实际长度(不包含\0), 返回的是字节数, 往往一个char就是一个字节, 因此可以视为长度
char s[10] = { 'A', 0, 'b', '\0', '0' };
printf("%zd", strlen(s));//这将返回1, 因为遇到0, 就认为字符串结束了
printf("%d", sizeof(s)/sizeof(char));//这将返回10, 表示整个数组
遇到特殊字符时:
char s[20] = "\t\t\nasdczx0\0qwe";
printf("%zd\n", strlen(s));//返回10 \t,\n分别被视为一个字符
printf("%d", sizeof(s)/sizeof(char));//返回20
char s[20] = "\x69\141\n"; // \xhh表示十六进制数代表的符号, \ddd表示八进制数代表的符号 一般不建议这样写
printf("%zd\n", strlen(s));
strcpy
字符串拷贝
strcpy(字符数组1,字符数组2)
- 将字符串2拷贝到字符串1中去, 返回字符数组1的首地址.(必须是字符串)
- 字符数组1必须足够大
strcat
字符串连接函数
strcpy(字符数组1,字符数组2)
- 将字符串2连接到字符串1后面, 返回字符数组1的首地址.(必须是字符串)
- 字符数组1必须足够大
- 连接之前,二者都是以
'\0'
结束的, 连接后 串1的'\0
取消,新串最后加'\0'
strcmp
字符串比较函数
strcmp(字符串1,字符串2)
- 比较规则: 两个字符串从左到右依次比较ASCII码值, 若
1<2
返回负整数, 若1==2
返回0, 若1>2
返回正整数. - 如果长度不等, 空的位置相当于和
\0
比 ,
注意: 字符串函数的使用前提必须是字符串或带'\0'
的字符数组, 否则将出现不可以预知的问题.
字符串函数的扩展用法
strncpy(p,p1,n)
复制指定长度的字符串
strncat(p,p1,n)
连接指定长度的字符串
strcasecmp
忽略大小写比较字符串
strncmp(p, p1, n)
比较指定长度字符串
strchr(p, c)
在字符串中查找指定字符
#include<stdio.h>
#include<string.h>
int main(int argc, char const* argv[])
{
char s1[]="123aeqw$asdsa";
int ch;
ch='$';
printf("%p,%p,\n\n",s1,strchr(s1,ch));
return 0;
}
strstr(p, p1)
查找字符串
#include<stdio.h>
#include<string.h>
int main(int argc, char const* argv[])
{
char s1[]="how are you";
char s2[]="are";
printf("%ld\n",strstr(s1,s2)-s1);
return 0;
}
关于字符的函数, 需要#include<ctype.h>
isalpha()
检查是否为字母字符
isupper()
检查是否为大写字母字符
islower()
检查是否为小写字母字符
isdigit()
检查是否为数字
指针
在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: 求阶乘
#include<stdio.h>
int calcu(int x);
int main()
{
printf("%d\n",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("%d\n",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;
}
函数指针
函数指针的核心是一个指针, 存储函数的地址
函数地址代表了函数的入口地址( 函数名)
#include<stdio.h>
int add(int, int);
int main()
{
int m = 10,n = 20;
int (*p)(int ,int );
p=add;
printf("%d\n",p(m,n));
return 0;
}
int add(int x,int y)
{
return x+y;
}
函数指针要与函数产生关系, 因此需要返回值类型和参数列表和函数的原型一致, 这里注意解引用 *
的优先级, 需要加()
函数指针数组
数组中函数指针指向函数的返回类型和参数列表一致.
例子: 调用qsort进行排序
#include<stdio.h>
#include<stdlib.h>
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("%d\n",a[k] );
}
return 0;
}
int stol(const void *x, const void *y)
{
return *(int *)x - *(int *)y;
}
资源&更深入的阅读资料:
领取资料的神秘通道开启点击链接加入群聊【C语言/C++编程学习基地】:828339809
边栏推荐
- ArrayList set
- LeetCode#118. Yanghui triangle
- LeetCode#268. Missing numbers
- Learning record: use STM32 external input interrupt
- Take you to use wxpy to create your own chat robot (plus wechat interface basic data visualization)
- ucore lab 6
- 線程及線程池
- How to write the bug report of software test?
- Introduction to safety testing
- Research Report on pharmaceutical R & D outsourcing service industry - market status analysis and development prospect forecast
猜你喜欢
Crawling cat's eye movie review, data visualization analysis source code operation instructions
ucore lab 2
Learning record: Tim - Basic timer
What is "test paper test" in software testing requirements analysis
STM32如何使用STLINK下载程序:点亮LED跑马灯(库版本)
MATLAB实例:阶跃函数的两种表达方式
51 lines of code, self-made TX to MySQL software!
Learning record: Tim - capacitive key detection
ucore lab7
What if software testing is too busy to study?
随机推荐
Servlet
ucore lab7
Collection collection and map collection
LeetCode#198. raid homes and plunder houses
12306: mom, don't worry about me getting the ticket any more (1)
ArrayList set
C4D quick start tutorial - creating models
Collection集合与Map集合
LeetCode#19. Delete the penultimate node of the linked list
China medical check valve market trend report, technical dynamic innovation and market forecast
Mysql database (IV) transactions and functions
Scoring system based on 485 bus
Mysql database (II) DML data operation statements and basic DQL statements
Introduction to safety testing
What are the commonly used SQL statements in software testing?
ucore lab5
Market trend report, technical innovation and market forecast of lip care products in China and Indonesia
LeetCode#62. Different paths
Report on the market trend, technological innovation and market forecast of printing and decorative paper in China
学习记录:TIM—基本定时器