c语言学习笔记
基础语法复习
c
数据类型
- unsigned取正数,否则是正负参半,0算在正数侧
- int范围大概到20w
- sizeof(xxx)获取所占字节数
♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥
输入输出
putchar()和getchar()
putchar
putchar(‘A’); //输出大写字母A
putchar(x); /*输出字符变量x的值*/
putchar(‘\n’); /*换行*/
成功返回ASCII码,失败返回EOF也就是-1
getchar
char c;
c = getchar();
返回读取到的字符
printf()和scanf()
格式词典
%c
输出一个单一的字符
%hd、%d、%ld
以十进制、有符号的形式输出 short、int、long 类型的整数
%hu、%u、%lu
以十进制、无符号的形式输出 short、int、long 类型的整数
%ho、%o、%lo
以八进制、不带前缀、无符号的形式输出 short、int、long 类型的整数
%#ho、%#o、%#lo
以八进制、带前缀、无符号的形式输出 short、int、long 类型的整数
%hx、%x、%lx
%hX、%X、%lX
以十六进制、不带前缀、无符号的形式输出 short、int、long 类型的整数。如果 x 小写,那么输出的十六进制数字也小写;如果 X 大写,那么输出的十六进制数字也大写。
%#hx、%#x、%#lx
%#hX、%#X、%#lX
以十六进制、带前缀、无符号的形式输出 short、int、long 类型的整数。如果 x 小写,那么输出的十六进制数字和前缀都小写;如果 X 大写,那么输出的十六进制数字和前缀都大写。
%f、%lf
以十进制的形式输出 float、double 类型的小数
%e、%le
%E、%lE
以指数的形式输出 float、double 类型的小数。如果 e 小写,那么输出结果中的 e 也小写;如果 E 大写,那么输出结果中的 E 也大写。
%g、%lg
%G、%lG
以十进制和指数中较短的形式输出 float、double 类型的小数,并且小数部分的最后不会添加多余的 0。如果 g 小写,那么当以指数形式输出时 e 也小写;如果 G 大写,那么当以指数形式输出时 E 也大写。
%s
输出一个字符串
- 总结
- c字符 s字符串 d整数 u无符号 f单精 lf双精 e科学计数
- o八进制 x十六进制
- 加h为short 加l为long 加#为添加多进制前缀
- x和e区分大小写(0x 0X这种)
- %5.2f表示输出至少五个位置(物理上,屏幕占的位置)留两位小数,不够的话前面是空白。
注:不想写5可以省略也可以用*代替,后面多加一个逗号注明
注:-5代表左对齐 - d、s这几个的.2就是实际的保留位数
printf()
int num = 5;
printf("您输入的数字是:%d",num);
返回值是显示的字符个数(在屏幕上占几位),失败返回一个负数
scanf()
int num;
scanf("请输入数字",&num);
返回值是成功读入的项目的个数,错误返回0,文件末尾返回EOF
- scanf可指定宽度不可指定精度
float a;
scanf(“%10f”,&a); //正确
scanf(“%10.2f”,&a); //错误
- %*d可以读取后不赋值,比如1,2就可以直接赋给俩变量且能读到’,‘
gets()和puts()
gets()
char str[100] = "\0";
gets(str);
- 优势在于,判断输入结束的标志为回车,因此可以读空格,但scanf读到空格也会终止
- 新标里被弃用,fgets(str,maxlen,stdin)代替
while (fgets(str, 10, stdin) != NULL){}
返回读取到的字符串的指针,错误返回空指针
puts()
char str[100] = "www.dotcpp.com";
puts(str);
拓展
头文件conio.h
- getch(); 只读取一个字符,输入不显示,不用回车确认!可用于输入密码时
- getche(); 只读取一个字符,输入显示,不用回车确认!
♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥
内存相关
存储单元分为内存和CPU寄存器
要存储的变量类型有auto extern static register
- 不专门声明的变量与形参都是auto,存储在动态存储区,函数调用时分配空间,调用结束自动释放。
- extern外部变量、也就是全局变量。
- static存储在静态区,仅初始化一次,函数调用完,它的值也不会删掉。
- register只能是局部变量、形参,不可用&取地址,因为它存储在CPU寄存器
变量的存储方式有静态和动态
数组
展开
int arr1[10];
float arr2[20];
char arr3[30]; //字符数组就是数组,字符串“abcdefg”默认末尾有个\0
- 二维数组是线性排布的,第一行、第二行。。。以此存储
string.h常用函数
char string[10];
char *str1 = "www.dotcpp.com"; //char * 表示指针类型的变量
//char str1[] = "www.dotcpp.com"也可以,str1是个指针,str1[]是个数组
strcpy(string, str1); //拷贝
strcat(string, str1); //拼接
//上述两个均在string基础上操作
int flag = strcmp(str1,str2); //从头到尾比较ascii
//1前面大 0一样 2后面大
char* ret = strchr(str,c); //查找c在str中第一次出现的位置
//ret等于包含该字母之后的字符串,ret-string以%d输出就是索引
int len = strlen(str);
//返回字符串长度
cpy() cmp() cat() 均可以加n,即strncpy...
指针与地址
用法
每一个变量占用不同字节,每个字节有一个地址,地址是一个16进制数字
#include<stdio.h>
int main()
{
int num=2014;
int *p=# //int*是一种叫指针的数据类型,p是变量名,是一个16进制数 数值上等于num的地址
printf("num地址=%#x,num=%d\n",&num,num);
printf("p=%#x,*p=%d\n",p,*p);
return 0;
}
// num地址= p num = *p
指针变量32位系统下占4字节,64位系统8字节
数组与指针
数组,&arr[0]表示该数组的地址,arr也代表该数组的地址
int arr[10];
//下面四种都是把arr地址赋给p
int *p = arr; //第一种
int *p = &arr[0];//第二种
int *p; p = arr; //第三种
int *p; p = &arr[0]; //第四种
(p+i)表示数组第i个元素的地址,因此*(p+i) = arr[i];
字符串和字符数组不同
char *arr = "abcdefg";
char arrr[] = "bcdefgh";
printf("%s %s %c",arr,arrr,arr[3]);
arr虽然是个指针变量,但他也可以直接当字符串用,只是不可以给arr[x]赋值
指针可以等于数组(各种数组都可以,区分int *还是char *)首地址、数组名(规定为数组首地址)、字符串常量(char * )
结构体
相当于自定义了一种数据类型
初始化赋值
#include<stdio.h>
struct stu
{
int age;
char name[];
};
int main()
{
struct stu A;
struct stu B = {18,"Tom"};
A.age = 20;
//结构体数组赋值,要么直接初始化,要么一个一个赋值,要么strcpy()
return 0;
}
结构体指针
给结构体初始化时,可以赋多个,比如
struct stu A[3] = {},{},{}
struct stu *p = &A[0];
//p->name访问,注意不是.
共用体
几种不同类型的变量存放在同一内存单元
- 后存的起作用,之前的失效
- 不能使用共同体,只能使用共同体里的元素
- 共用体不可初始化,因为不能对一个内存单元同时赋值
typedef
替换
typedef int A;
A a = 10; //a是int型 值为10
省略struct
typedef struct stu
{
int age;
char name[12];
}s;
struct stu A;
s A;//s等价替换了struct stu
枚举类型
简化宏定义
#define MON 1
#define TUE 2
#define WED 3
#define THU 4
#define FRI 5
#define SAT 6
#define SUN 7
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
enum DAY day;
day = WED;
printf("%d",day);
预处理
带#的都是预处理,包括头文件、宏定义、条件编译
宏定义
嵌套容易出错!!亲测宏定义max嵌套后功能出错,猜测是因为先替换再计算导致
#define PI 3.14; 可以!
#define A B; 可以!
#define M(x) x+1; 可以!
#define max(a.b) a>b?a:b; 可以!
//相比于函数调用 宏定义效率更高!
//语句可以是多句,逗号隔开!!
包含头文件
<> “”都可以 尖括号从include文件夹查找,双引号从当前源文件查找
条件编译
如果标识符是define,就编译程序段1,否则编译程序段2,其中else可以没有
#ifdef 标识符
程序段 1
#else
程序段 2
#endif
//ifndef和上述相反
//标识符处可以是常量,判真假决定是否编译
#和##
相当于粘合剂,
#include <stdio.h>
#define v(x) var##x
//把var(x) 转换为varx!!
int main() {
int var1 = 10;
printf("%d\n", a(1));
return 0;
}
printf中,放再多的""也会被合并成一个!但用逗号隔开后,逗号后面的就不会打印了!!
#include<stdio.h>
#define SUM(A, B) printf("A+B=%d\n",(A)+(B))
//#define SUM(A, B) printf(#A "+" #B "=%d\n",(A)+(B))
int main()
{
SUM(3, 5);
return 0;
}
//对于这段代码来说,A+B=属于const char*,不会被替换为3+5,只会显示A+B=8,要想替换就要用#
//本质上,预编译阶段会把#A替换为"A"
#include<stdio.h>
#define PrintStr(A) printf(#A)
int main()
{
PrintStr(你好,C语言\n再见,C语言);
return 0;
}
强制类型转换
(int)和(int&)强制转换的区别是前者会对数据进行转换,后者是把内存单元的值直接用int型输出
- char转int(或unsigned int); 正数,高位补0,负数,高位补1;即转换后结果一样;
- unsigned char 转(int或unsigned int );高位均补0;
- -int(或 unsigned int ) 转(char或unsigned char); 直接取最低8位
- 浮点转整型,直接取整数;
- 整型转浮点,加.0;
细节与技巧
- printf("%%")输出一个%
- sizeof()是单目运算符,关键字并非函数,可以运算任何数据类型关键字或变量名
- while(i++<20){}替换for循环
- 嵌套for循环,里面的for条件j<=i省去if判断
- continue只能在循环里使用,break还可以在switch中使用
- c++的string直接+就可以拼接了!!不用strcat!!
- sizeof()一个数组,得到的是strlen()长度+1,因为末位还有个\0
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现