当前位置:网站首页>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集合
- How to write the bug report of software test?
- Collection collection and map collection
- 学习记录:使用STM32外部输入中断
- Do you know the advantages and disadvantages of several open source automated testing frameworks?
- LeetCode#198. raid homes and plunder houses
- LeetCode#2062. Count vowel substrings in strings
- Lab 8 文件系统
- MATLAB实例:阶跃函数的两种表达方式
- 51 lines of code, self-made TX to MySQL software!
猜你喜欢
ucore lab7
Leetcode notes - dynamic planning -day6
Learning record: Tim - Basic timer
基于485总线的评分系统
Learning record: understand systick system timer and write delay function
Crawler series of learning while tapping (3): URL de duplication strategy and Implementation
Do you know the performance testing terms to be asked in the software testing interview?
ucore lab 6
What is "test paper test" in software testing requirements analysis
JS --- all knowledge of JS objects and built-in objects (III)
随机推荐
MySQL transactions
Indonesian medical sensor Industry Research Report - market status analysis and development prospect forecast
学习记录:TIM—电容按键检测
51 lines of code, self-made TX to MySQL software!
Introduction to safety testing
Preface to the foundations of Hilbert geometry
Matlab example: two expressions of step function
Medical colposcope Industry Research Report - market status analysis and development prospect forecast
Portapack application development tutorial (XVII) nRF24L01 launch B
Learning records: serial communication and solutions to errors encountered
[pytorch] simple use of interpolate
Leetcode notes - dynamic planning -day6
ucorelab4
ArrayList集合
Stm32 dossiers d'apprentissage: saisie des applications
Learning record: use STM32 external input interrupt
ucorelab3
Research Report of pharmaceutical solvent industry - market status analysis and development prospect prediction
LeetCode#204. Count prime
Cost accounting [20]