linux C编程随笔

设置终端字体

\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 *ppint*类型,const修饰的是*p,所以*p是常量,表示p指向的地址里的值不可修改,也就是说,p里的值不能再重新赋值了,但是可以修改p指向的地址,指向的值还是不变。

int a = 10;
int b = 20;
const int *p = &a;
p = &b;      // 可以
*p = 100;    // 错误

指针常量int * const p

pint*类型,那么const修饰的是p,所以p是常量,表示p指向的地址不可修改,即p不能再指向别的地方了,但是可以修改p指向的这个地址里的值。

int a = 10;
int b = 20;
int * const p = &a;
p = &b;      // 错误
*p = 100;    // 允许
No.例子名称指向的值地址
1const int *p/int const *p常量指针(指向常量的指针)不可改变可改变
2int* const p指针常量(指针是常量)可改变不可改变
3const 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语言里,结构体所占的内存是连续的,但是各个成员之间的地址不一定是连续的。所以就出现了"字节对齐"。

  • 字节对齐默认原则

    1. 结构体变量的大小,一定是其最大的数据类型的大小的整数倍,如果某个数据类型大小不够,就填充字节。
    2. 结构体变量的地址,一定和其第一个成员的地址是相同的。
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

  1. 局部变量、静态变量、动态分配内存、字符串常量与函数分别放在一起,即使在不同的函数中。
  2. 变量的存放地址大小有如下特点:

    字符串常量与代码 < 静态变量 < 动态分配内存 < 局部变量

  3. 静态变量、动态分配内存、字符串常量与函数的相邻变量地址是递增的。局部变量相邻变量地址是递减的。
  4. 字符串常量与函数是在一起的。

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缺点只能在函数内部使用。容易造成内存泄露。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值