C语言:笔记202305

C语言:大伟笔记202305

变量作用域(scope)

  1. 代码块作用域 :{}

  2. 文件作用域 :写的地方到文件结束

  3. 原型作用域 :函数原型声明的时候的变量名可以随便 写

  4. 函数作用域 :配合goto语句的标签

链接属性

​ 编译器编译c源码和基础库做链接,生成可执行程序。

  • external 可以去别的文件里面去找具有文件作用域的对象
  • internal 用static关键字来限制external对象,限制后只能本文件内访问
  • none 代码块变量是空链接属性

生存期

  • 静态存储期 (static storage duration):文件作用域,程序退出释放。
  • 自动存储期 (automatic storage duration): 代码块作用域,代码块结束时效

变量存储类型

  1. auto :自动存储区,代码块中的变量默认是atuo类型
  2. register : 自动存储区,寄存器变量是有可能存储在cpu内部的
  3. static : 静态存储区,静态局部变量的生存期和全局变量一样但是作用域还是块
  4. extern : 声明外部再找找
  5. typedef : 对类型的封装,给类型取别名,配合结构体使用更方便

关键字struct

#include <stdio.h>
#include <stdlib.h>

struct Date
{
    int year;
    int mouth;
    int day;
};

int main(void)
{
    struct Date *date;
    date = (struct Date *)malloc(sizeof(struct Date));
    if (date == NULL)
    {
        printf("内存分配失败\n");
        exit(1);
    }
    date->year = 2023;
    date->mouth = 5;
    date->day = 20;
    printf("%d-%d-%d", date->year, date->mouth, date->day);
    return 0;
}

关键字typedef

#include <stdio.h>
#include <stdlib.h>

typedef struct Date
{
    int year;
    int mouth;
    int day;
} DATE, *P_DATE;

int main(void)
{
    P_DATE date;
    date = (P_DATE)malloc(sizeof(DATE));
    if (date == NULL)
    {
        printf("内存分配失败\n");
        exit(1);
    }
    date->year = 2023;
    date->mouth = 5;
    date->day = 20;
    printf("%d-%d-%d", date->year, date->mouth, date->day);
    return 0;
}

指针函数和函数指针

#include <stdio.h>

/*
    函数指针            int (*fp)(int, int)
    函数指针作入参       
    函数指针作返回值  
*/

int add(int, int);
int sub(int, int);
int compt(int (*)(int,int),int,int);
int (*select(char))(int, int);

int add(int a,int b){
    return a+b;
}
int sub(int a,int b){
    return a-b;
}

// 函数指针作入参的例子
int compt(int (*fp)(int,int),int a,int b){
    return (*fp)(a,b);
}

// 函数指针作返回值的例子
int (*select(char o))(int a,int b){
    switch (o)
    {
    case '+':
        return add;
    case '-':
        return sub;
    }
}

int main(){
    int rest;

    // 函数指针作入参的例子
    rest = compt(add,1,2);
    printf("a+b = %d\n",rest);
    rest = compt(sub,1,2);
    printf("a-b = %d\n",rest);

    // 函数指针作返回值的例子
    char o;
    int a,b;
    int (*fp)(int, int);
    printf("请输入计算式(例如2+3):");
    scanf("%d%c%d",&a,&o,&b);
    fp = select(o);
    rest = compt(fp,a,b);
    printf("rest = %d\n",rest);   
}

递归

​ 函数调用它本身。递归必须要有结束条件,否则程序会崩溃。

#include <stdio.h>

void func01(int);

void func01(int n)
{
    printf("%d aaaa\n",n);
    if (--n)
    {
        func01(n);
    }
}

int main(void)
{
    func01(3);
    func01(3);
}
#include <stdio.h>

long func01(int);

long func01(int n)
{
    long m;
    if (n > 0)
    {
        m = n * func01(n-1);
    }
    else
    {
        m = 1;
    }
    return m;
}

int main(void)
{
    long int a = func01(5);
    printf("%d\n", a);
    long int b = func01(5);
    printf("%d\n", b);
}

快速排序

​ 快速排序算法的基本思想是:通过一趟排序将待排序数据分割成独立的两个部分,其中一部分的所有元素均比另一部分的元素小,然后分别对这两部分继续进行排序,重复上述步骤直到排序完成。

#include <stdio.h>

void print_list(int *int01, int length)
{
    int i;
    for (i = 0; i < length; i++)
    {
        printf("%d ", *int01++);
    }
    printf("\n");
}

void quick_sort(int array[], int left, int right)
{
    int i = left, j = right;
    int temp;
    int pivot;
    pivot = array[(left + right) / 2];
    while (i < j)
    {
        // 从左到右找到大于等于基准点的元素
        while (array[i] < pivot)
        {
            i++;
        }
        // 从右到左找到小于等于基准点的元素
        while (array[j] > pivot)
        {
            j--;
        }
        printf("currnt: %d,%d\n", i, j);
        // 如果i<=j,则互换
        if (i <= j)
        {
            temp = array[i];
            array[i] = array[j];
            array[j] = temp;
            i++;
            j--;
        }
    }
    print_list(&array[0], 9);
    if (left < j)
    {
        printf("\n  sort right array[%d,%d]\n", left, j);
        quick_sort(array, left, j);
    }
    if (i < right)
    {
        printf("\n  sort left array[%d,%d]\n", i, right);
        quick_sort(array, i, right);
    }
}



int main(void)
{
    int array[] = {9, 1, 8, 3, 7, 2, 6, 5, 4};
    int i, length;

    length = sizeof(array) / sizeof(array[0]);

    printf("\n  sort all array[%d,%d]\n", 0, length-1);
    quick_sort(array, 0, length - 1);
    print_list(&array[0], length);

    return 0;
}

内存管理函数

  1. malloc 申请动态内存空间 viod *malloc(size_t size); 在堆上,需要手动释放。

  2. free 释放动态内存空间 void free(void *ptr);释放堆上的内存

  3. calloc 申请并初始化一系列内存空间 void *calloc(size_t nmemb, size_t size);初始为0。

  4. realloc 重新分配内存空间 viod *realloc(void *ptr, size_t size);重新分配并拷贝。

    (注明: 普通的局部变量在栈上。)

  5. memset 使用一个常量字节填充内存空间 memset(ptr, 0, N * sizeof(int));

  6. memcpy 拷贝内存空间 memcpy(prt2,prt1,N); free(ptr1);

  7. memmove 拷贝内存空间

  8. memcmp 比较内存空间

  9. memchr 在内存空间中搜索一个字符

根据用户输入动态扩容内存的例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{

    int num, i;
    int count = 0;
    int *ptr = NULL;
    do
    {
        printf("input number: ");
        scanf("%d", &num);
        count++;
        ptr = (int *)realloc(ptr, count * sizeof(int));
        if (ptr == NULL)
        {
            exit(1);
        }
        ptr[count - 1] = num;
    } while (num != -1);

    for (i = 0; i < count; i++)
    {
        printf("%d ", ptr[i]);
    }
    putchar('\n');
    free(ptr);
    return 0;
}

内存布局

#include <stdio.h>
#include <stdlib.h>

int global_uninit_var;
int global_init_var1 = 520 ;
int global_init_var2 = 880 ;

void func(void);
void func(void){
	;
}

int main(void){
	int local_var1;
	int local_var2;
	
	static int static_uninit_var;
	static int static_init_var = 456;
	
	char *str1 = "1111";                   //字符串常量
	char *str2 = "2222";
	char str3[5] = {'a','b','1','2','\0'}; //局部变量
	char str4[5] = {'a','b','1','2','\0'}; 
	
	int *malloc_var = (int *)malloc(sizeof(int));
	
    printf("addr of local_var1 ->        %p\n",&local_var1);
	printf("addr of local_var2 ->        %p\n",&local_var2);
    printf("addr of str3 ->              %p\n",str3);
    printf("addr of str4 ->              %p\n",str4);
	printf("addr of malloc_var ->        %p\n",malloc_var);
	printf("addr of global_uninit_var -> %p\n",&global_uninit_var);
	printf("addr of static_uninit_var -> %p\n",&static_uninit_var);
	printf("addr of static_init_var ->   %p\n",&static_init_var);
	printf("addr of global_init_var2 ->  %p\n",&global_init_var2);
	printf("addr of global_init_var1 ->  %p\n",&global_init_var1);
	printf("addr of str2 ->              %p\n",str2);
	printf("addr of str1 ->              %p\n",str1);
	printf("addr of func ->              %p\n",func);

	
	return 0;
}
[root@wei07 c]# gcc t.c -o t && ./t
addr of local_var1 ->        0x7ffc0d64f00c
addr of local_var2 ->        0x7ffc0d64f008
addr of str3 ->              0x7ffc0d64f000
addr of str4 ->              0x7ffc0d64eff0
addr of malloc_var2 ->       0x1d32030
addr of malloc_var1 ->       0x1d32010
addr of global_uninit_var -> 0x601050
addr of static_uninit_var -> 0x60104c
addr of static_init_var ->   0x601044
addr of global_init_var2 ->  0x601040
addr of global_init_var1 ->  0x60103c
addr of str2 ->              0x4007a5
addr of str1 ->              0x4007a0
addr of func ->              0x40057d
[root@wei07 c]#

变量名称变量类型内存地址内存段
local_var1局部变量高(大)栈stack
local_var2局部变量栈stack
str3[]局部变量栈stack
str4[]局部变量栈stack
malloc_var2动态申请的内存空间堆heap
malloc_var1动态申请的内存空间堆heap
global_uninit_var全局变量(未初始化)BSS
static_uninit_var静态变量(未初始化)BSS
static_init_var静态变量(初始化)数据段
global_init_var2全局变量(初始化)数据段
global_init_var1全局变量(初始化)数据段
str2字符串常量代码段
str1字符串常量代码段
func函数低(小)代码段

注明1:BSS是英文Block Started by Symbol的简称,这个区段的数据在程序运行前将被自动初始化为数字0.

注明2:linux命令size,显示程序的text,data,bss段的大小。程序的本质就是这3个段。

注明3:堆和栈的区别 ( 堆由程序员手动申请,栈由系统自动分配;堆到主动释放时结束,栈到局部函数返回时结束;不同函数可以自由访问堆,不同函数不能相互访问栈;堆由低往高用,栈由高往低用,他们共享一片蓝天。)

D:\soft\src\Python3\C>gcc t.c -o t && t
addr of local_var1 ->        000000000061FDFC
addr of local_var2 ->        000000000061FDF8
addr of str3 ->              000000000061FDF3
addr of str4 ->              000000000061FDEE
addr of malloc_var2 ->       0000000000736BD0
addr of malloc_var1 ->       0000000000736BB0
addr of global_uninit_var -> 0000000000407970
addr of static_uninit_var -> 0000000000407030
addr of static_init_var ->   0000000000403018
addr of global_init_var2 ->  0000000000403014
addr of global_init_var1 ->  0000000000403010
addr of str2 ->              0000000000404005
addr of str1 ->              0000000000404000
addr of func ->              0000000000401550

D:\soft\src\Python3\C>

UNIX接口-低级IO-read和write

#include "stdio.h"
#include "unistd.h"

#define BUF 6

void copy01();
int getchar01();
int getchar02();

int main()
{
    copy01();

    char c;
    c = getchar01();
    printf("%c\n", c);
    c = getchar01(); // 等待read
    printf("%c\n", c);

    c = getchar02();
    printf("%c\n", c);
    c = getchar02();
    c = getchar02();
    c = getchar02(); // 要么从缓存里面取,要么等待read
    c = getchar02();
    c = getchar02();
    c = getchar02();
    printf("%c\n", c);

    // 注明: 
    //      如果把getchar02放到01前面执行,02会一次性尽量读取BUFSIZE512个字符,
    //      会发现01要等待第二次的标准输入。
    return 0;
}

/* 复制标准输入到标准输出 */
void copy01(void)
{
    char exit0 = '0';
    char buf[BUF];
    int n;
    printf("请输入内容,回车结束。输入0时,退出复制。\n");
    while ((n = read(0, buf, BUF)) > 0)
    {
        if (buf[0] == exit0)
        {
            printf("退出。\n");
            break;
        }
        write(1, buf, n);
    }
}

/* 不带缓冲的getchar */
int getchar01(void)
{
    char c;
    return (read(0, &c, 1) == 1) ? (unsigned char)c : EOF;
}

/* 带缓冲的getchar */
int getchar02(void)
{
    static char buf[BUFSIZ];
    static char *bufp = buf;
    static int n = 0;
    if (n == 0)
    {
        n = read(0, buf, sizeof(buf));
        bufp = buf;
    }
    return (--n >= 0) ? (unsigned char)*bufp++ : EOF;
}

共用体union

​ 特殊的结构体,里面的所有成员共用同一个地址,同一时间只能用里面的一个成员。

union Test{
    int t;
    double pi;
    char str[6];
};

时间tm结构

#include <time.h>
int main(void){
    strcut tm *p;
    time_t t;
    time(&t);          //秒数赋值
    p = localtime(&t); //tm结构体赋值
    return 0;
}
struct tm {
   int tm_sec;         /* 秒,范围从 0 到 59        */
   int tm_min;         /* 分,范围从 0 到 59        */
   int tm_hour;        /* 小时,范围从 0 到 23        */
   int tm_mday;        /* 一月中的第几天,范围从 1 到 31    */
   int tm_mon;         /* 月,范围从 0 到 11        */
   int tm_year;        /* 自 1900 年起的年数        */
   int tm_wday;        /* 一周中的第几天,范围从 0 到 6    */
   int tm_yday;        /* 一年中的第几天,范围从 0 到 365    */
   int tm_isdst;       /* 夏令时                */
};

枚举类型enum

​ 如果一个变量有且仅有几种值,那么就适合用枚举类型。

int main(void){
    enum Week {sun,mon,tue,wed,thu,fri,sat};
    enum Week today;
    strunt tm *p;
    time_t t;
    time(&t);
    p=localtime(&t);
    today=p->tm_wday;
    return today;
}

注明:枚举就是符号常量,默认0,1,2,3…; 可以定义枚举类型的时候修改默认值,修改后呈现两面派:0,1,12,13…

位域(:节约空间)

​ 位域是一个成员站用几个2进制位。

struct Test{
	unsigned int a:1;
    unsigned int b:1;
    unsigned int c:2;
};

位运算

  • ~ 按位取反

  • & 按位与

  • ^ 按位非

  • | 按位或

注明:配合掩码使用很好。

移位运算

​ value << 2 ; 左移2位

​ value >> 2 ; 右移2位

打开和关闭文件

fp = fopen("aaa.txt","r");
fclose(fp);

​ 参考网站: https://fishc.com.cn/thread-90808-1-1.html

// 函数原型
#include <stdio.h>
...
FILE *fopen(const char *path, const char *mode);

参数解析:

参数含义
path该参数是一个 C 语言字符串,指定了待打开的文件路径和文件名
mode“r” …如下

“r” 1. 以只读的模式打开一个文本文件,从文件头开始读取 2. 该文本文件必须存在

"w"1. 以只写的模式打开一个文本文件,从文件头开始写入 2. 如果文件不存在则创建一个新的文件 3. 如果文件已存在则将文件的长度截断为 0(重新写入的内容将覆盖原有的所有内容)

"a"1. 以追加的模式打开一个文本文件,从文件末尾追加内容 2. 如果文件不存在则创建一个新的文件

"r+"1. 以读和写的模式打开一个文本文件,从文件头开始读取和写入 2. 该文件必须存在 3. 该模式不会将文件的长度截断为 0(只覆盖重新写入的内容,原有的内容保留)

"w+"1. 以读和写的模式打开一个文本文件,从文件头开始读取和写入 2. 如果文件不存在则创建一个新的文件 3. 如果文件已存在则将文件的长度截断为 0(重新写入的内容将覆盖原有的所有内容)

"a+"1. 以读和追加的模式打开一个文本文件 2. 如果文件不存在则创建一个新的文件 3. 读取是从文件头开始,而写入则是在文件末尾追加

"b"1. 与上面 6 中模式均可结合(“rb”, “wb”, “ab”, “r+b”, “w+b”, “a+b”) 2. 其描述的含义一样,只不过操作的对象是二进制文件

返回值:

  1. 如果文件打开成功,则返回一个指向 FILE 结构的文件指针;

  2. 如果文件打开失败,则返回 NULL 并设置 errno 为指定的错误。

顺序读写文件

读写单个字符
int __cdecl fgetc(FILE *_File);
int __cdecl fputc(int _Ch,FILE *_File);
读写字符串
char *__cdecl fgets(char * __restrict__ _Buf,int _MaxCount,FILE * __restrict__ _File);
int __cdecl fputs(const char * __restrict__ _Str,FILE * __restrict__ _File);

​ 注明1:_MaxCount是字符数量+1,因为末尾自动添加’\0’再返回。

​ 注明2:如果没有到达_MaxCount就遇到了’\n’,则只读取到’\n’。

格式化读写文件
int __cdecl fprintf(FILE * __restrict__ _File,const char * __restrict__ _Format,...);
int __cdecl fscanf(FILE * __restrict__ _File,const char * __restrict__ _Format,...) __MINGW_ATTRIB_DEPRECATED_SEC_WARN;
指定尺寸读写文件
size_t __cdecl fread(void * __restrict__ _DstBuf,size_t _ElementSize,size_t _Count,FILE * __restrict__ _File);
size_t __cdecl fwrite(const void * __restrict__ _Str,size_t _Size,size_t _Count,FILE * __restrict__ _File);

随机读写文件

  • 获取位置指示器的位置

    long __cdecl ftell(FILE *_File);
    
  • 设置位置指示器的位置

    int __cdecl fseek(FILE *_File,long _Offset,int _Origin);
    
    #define SEEK_CUR 1
    #define SEEK_END 2
    #define SEEK_SET 0
    

错误号打印

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main(void){
    FILE *fp;
    if ((fp = fopen("aaa.txt","r")) == NULL){
        perror("打开文件失败");
        fprintf(stderr,"错误:%s \n打开文件失败。\n",strerror(errno));
        exit(EXIT_FAILURE);
    }
    fclose(fp);
    return 0;
}

​ 注明: perror 和 strerror(errno) ,二选一。

IO缓冲区

  • 手动刷新缓冲区: fflush
  • 设置缓冲区参数: setvbuf
  • 按块缓存 _IOFBF
  • 按行缓存 _IOLBF
  • 不缓存 _IONBF
int __cdecl fflush(FILE *_File);
int __cdecl setvbuf(FILE * __restrict__ _File,char * __restrict__ _Buf,int _Mode,size_t _Size);
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值