设置终端字体
\033[背景颜色号;字体颜色号m字符串\033[0m
1 #include<stdio.h>
2 main(){
3 printf("\033[30;37mhello world\033[0m");
4 }
前景色
颜色 | 代码 |
---|---|
黑色前景 | 30 |
红色前景 | 31 |
绿色前景 | 32 |
棕色前景 | 33 |
蓝色前景 | 34 |
紫色前景 | 35 |
青色前景 | 36 |
白色前景 | 37 |
背景色
颜色 | 代码 |
---|---|
黑色背景 | 40 |
红色背景 | 41 |
绿色背景 | 42 |
棕色背景 | 43 |
蓝色背景 | 44 |
紫色背景 | 45 |
青色背景 | 46 |
白色背景 | 47 |
char 1个字节
int、float4个字节
double\long long 8个字节
数组名可以当指针地址用
随机数产生
如何每次产生不一致的随机数:
srand((int)time(0));//用系统时间来做种子
rand()和srand()函数。这二个函数的工作过程如下:
1) 首先给srand()提供一个种子,它是一个unsigned int类型,其取值范围从0~65535;
2) 然后调用rand(),它会根据提供给srand()的种子值返回一个随机数(在0到32767之间)
3) 根据需要多次调用rand(),从而不间断地得到新的随机数;
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void main()
{
srand((int)time(0));//使用系统时间作为随机种子
int x;
int j;
for(x=0;x<10;x++)
printf("%d\t",rand_X(100));//输出100内的随机数
}
int rand_X(int x)
{
return rand()%x;
}
[root@foundation38 C_code]# gcc 随机数.c && ./a.out
47 89 29 31 96 38 61 41 53 2
[root@foundation38 C_code]# gcc 随机数.c && ./a.out
7 4 75 14 15 73 98 61 7 92
要让随机数限定在一个范围,可以采用模除加法的方式。
要产生随机数r, 其范围为 X<=r<=Y,可以使用如下公式:
rand()%(Y-X+1)+X
其原理为,对于任意数,
0<=rand()%(Y-X+1)<=Y-X
于是
0+X<=rand()%(Y-X+1)+X<=Y-X+X
即
X<=rand()%(Y-X+1)+X<=Y
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void main()
{
srand((int)time(0));//使用系统时间作为随机种子
int x;
int j;
for(x=0;x<10;x++)
printf("%d\t",rand_X());//输出20~2内的随机数
printf("\n");
}
int rand_X()
{
return rand()%(20-2+1)+2;
}
归并
https://blog.csdn.net/ds19980228/article/details/82863531
atoi 转为整型
echo $? ##显示返回值,比如return 0,结果就是0
*p++与*++p与++*p
1 #include <stdio.h>
2
3 int main(){
4
5 int nu[]={1,2,3,4,5,6,7};
6 int* p,q;
7 p=nu;
8 printf("%d",sizeof(nu)/sizeof(nu[0]));
9 for(int i=0;i<sizeof(nu)/sizeof(nu[0]);i++)
10 {
11 printf("%d\n",*p++);
12 }
13 return 0;
14 }
*p++输出p当前位置的数,然后指针p指向下一个位置
*++p输出的是指针p指向的下一个位置的数
++*p输出指针p位置的数值加一
指针类型不同,步进大小不同
20 char* str="abcdef";
21 int* p=(int*)str;
22 p++;
23 char* q=(char*)p;
24 printf("%c\n",*q);
输出是‘e’
20 char* str="abcdef";
21 int* p=(int*)str;
22 p++;
23 char* q=(char*)p;
24 printf("%c\n%p\n",*q--,q--);
25 printf("%c\n%p\n",*q++,q++);
26 printf("%c\n%p\n",*q++,q++);输出结果:
d
0x400797
d
0x400795
f
0x400797
指针数组
指针是一个类型,也可以组成一个数组,这样的数组称为指针数组。
#include <stdio.h>
int main(){
int a = 1;
int b = 2;
int c = 3;
int* p[] = {&a,&b,&c};
for(int i=0;i<3;++i){
printf("%d\n",*p[i]);
}
for(int i=0;i<3;++i){
printf("%d\n",**(p+i));
}
}
[]
的优先级高于*
,那么p
先和[]
结合,说明这是一个数组。再和int*
结合,说明这个数组里的每个元素都是一个指针,每个元素都能保存一个地址。
常量指针const int *p
可以写作int const *p
,p
是int*
类型,const
修饰的是*p
,所以*p
是常量,表示p
指向的地址里的值不可修改,也就是说,p
里的值不能再重新赋值了,但是可以修改p
指向的地址,指向的值还是不变。
int a = 10;
int b = 20;
const int *p = &a;
p = &b; // 可以
*p = 100; // 错误
指针常量int * const p
p
是int*
类型,那么const
修饰的是p
,所以p
是常量,表示p
指向的地址不可修改,即p
不能再指向别的地方了,但是可以修改p
指向的这个地址里的值。
int a = 10;
int b = 20;
int * const p = &a;
p = &b; // 错误
*p = 100; // 允许
No. | 例子 | 名称 | 指向的值 | 地址 |
---|---|---|---|---|
1 | const int *p /int const *p | 常量指针(指向常量的指针) | 不可改变 | 可改变 |
2 | int* const p | 指针常量(指针是常量) | 可改变 | 不可改变 |
3 | const int * const p | 常量指针常量 | 不可改变 | 不可改 |
const int *p,*q;
int const *p,*q;
int* const p,*q;
const int * const p,*q;
const int *p,*q;
int const *p,*q;
int* const p,*q;
const int * const p,*q;
函数指针
函数指针是指向函数的指针变量,即本质是一个指针变量。
定义的方式如下:
类型说明符 (*函数名) (参数)
其实这里不能称为函数名,应该叫做指针的变量名。这个特殊的指针指向一个返回整型值的函数。指针的声明笔削和它指向函数的声明保持一致。
指针名和指针运算符外面的括号改变了默认的运算符优先级。如果没有圆括号,就变成了一个返回整型指针的函数的原型声明。
数组名即数组的指针,函数名也是函数的指针。
例如:
void (*fptr)();
- 赋值
把函数的地址赋值给函数指针,可以采用下面两种形式:
函数名即函数地址。这两种赋值方式完全一样。fptr = func; fptr = &func;
- 调用
函数指针调用也可以采用下面两种形式:
这两种调用方式完全一样。第二种格式看上去和函数调用无异。但是有些程序员倾向于使用第一种格式,因为它明确指出是通过指针而非函数名来调用函数的。(*fptr)(); fptr();
回调函数实例:
#include <stdio.h>
int add(int a,int b)
{return a+b;}
int cheng(int a,int b)
{return a*b;}
int yunsuan(int *arry,int num,int(*huidiao)(int,int)) //(*huidiao)是一个回调函数
{
int out=arry[0];
for(int i=1;i<num;i++)
{
out=(*huidiao)(out,arry[i]);
}
return out;
}
int main(int argc,char* argv[])
{
int input[]={1,2,3,4,5};
printf("%d\n",yunsuan(input,5,add)); //回调函数是一个自己传参的过程
printf("%d\n",yunsuan(input,5,cheng));
return 0;
}
结构体指针访问成员
结构体指针访问成员的方式与结构体变量访问成员的方式有区别。
结构体变量使用.
和名字访问成员。
结构体指针使用->
和名字访问成员。
格式如下:
结构体指针->成员名
例如:
struct Point3D p = {1,2,3};
struct Point3D* q = &p;
printf("(%d,%d,%d)",q->x,q->y,q->z);
示例
按从低到高的顺序打印出int
类型每个字节的对应的数值(十六进制)。
union IntByte{
int n;
char c[sizeof(int)];
};
union IntByte b;
b.n = 1234;
int i;
printf("%08X\n",b.n);
for(i=0;i<sizeof(int);++i){
printf("%02hhX",b.c[i]);
}
printf("\n");
结构体字节对齐
struct S1{
char c1;
char c2;
int n;
};
struct S2{
char c1;
int n;
char c2;
};
printf("sizeof(struct S1) = %ld\n",sizeof(struct S1));
printf("sizeof(struct S2) = %ld\n",sizeof(struct S2));
在C语言里,结构体所占的内存是连续的,但是各个成员之间的地址不一定是连续的。所以就出现了"字节对齐"。
-
字节对齐默认原则
- 结构体变量的大小,一定是其最大的数据类型的大小的整数倍,如果某个数据类型大小不够,就填充字节。
- 结构体变量的地址,一定和其第一个成员的地址是相同的。
struct Box{ //size=4x8=32
int height;
char a[10];
double width;
char type;
};
int main(void) {
struct Box box;
printf("box = %p\n", &box);
printf("box.height = %p\n", &box.height);
printf("box.a = %p\n", box.a);
printf("box.width = %p\n", &box.width);
printf("box.type = %p\n", &box.type);
printf("box = %d\n", sizeof(box));
return 0;
}
[root@foundation38 C_code]# gcc duiqi.c && ./a.out
box = 0x7ffd41445e50
box.height = 0x7ffd41445e50
box.a = 0x7ffd41445e54
box.width = 0x7ffd41445e60
box.type = 0x7ffd41445e68
box = 32
- 局部变量、静态变量、动态分配内存、字符串常量与函数分别放在一起,即使在不同的函数中。
- 变量的存放地址大小有如下特点:
字符串常量与代码 < 静态变量 < 动态分配内存 < 局部变量
- 静态变量、动态分配内存、字符串常量与函数的相邻变量地址是递增的。局部变量相邻变量地址是递减的。
- 字符串常量与函数是在一起的。
2.1 栈区(stack)
由编译器自动分配和释放,主要是存放函数参数的值,局部变量的值。
2.2 堆区(heap)
由程序员自己申请分配和释放,需要malloc()
、calloc()
、realloc()
函数来申请,用free()
函数来释放如果不释放,可能出现指针悬空/野指针。
函数不能返回指向栈区的指针,但是可以返回指向堆区的指针。
2.3 数据区(data)
变量标有static
关键字,保存了静态变量。
1. 初始化的全局变量和初始化的静态变量,在一块区域;
2. 未初始化的全局变量和未初始化的静态变量,在一块区域,称作BSS(Block Started by Symbol:以符号开始的块);
3. 静态变量的生命周期是整个源程序,而且只能被初始化一次,之后的初始化会被忽略。
(如果不初始化,数值数据将被默认初始化为0
, 字符型数据默认初始化为NULL
)。
整个数据区的数组,在程序结束后由系统统一销毁。
2.4 代码区(code)
用于存放编译后的可执行代码,二进制码,机器码。
堆和栈的区别
No. | 比较方面 | 栈 | 堆 |
---|---|---|---|
1 | 管理方式 | 由系统自动管理,以执行函数为单位 | 由程序员手动控制 |
2 | 空间大小 | 空间大小编译时确定(参数+局部变量) | 具有全局性,总体无大小限制。 |
3 | 分配方式 | 函数执行,系统自动分配;函数结束,系统立即自动回收。 | 使用new /malloc() 手动分配释放;使用delete /free() 手动释放 |
4 | 优点 | 使用方便,不需要关心内存申请释放。 | 可以跨函数使用。 |
5 | 缺点 | 只能在函数内部使用。 | 容易造成内存泄露。 |