C语言基础(malloc、free、calloc、realloc;内存泄露;字符串处理函数;const)

动态申请函数

malloc、free、calloc、realloc

malloc 申请内存
free 释放空间
野指针问题防范

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

// malloc 申请的内存,内存中存放的内容是随机的,不确定的;
// 而calloc函数申请的内存中的内容为0

char *fun()
{
    // char ch[100] = "hello world";

    // 静态全局区的空间只要开辟好,除非程序结束否则不会释放
    // static char ch[100] = "hello world";

    // 堆区开辟空间,手动申请手动释放,更加灵活
    char *str = (char *)malloc(100 * sizeof(char));
    str[0] = 'h';
    str[1] = 'e';
    str[2] = 'l';
    str[3] = 'l';
    str[4] = 'o';
    str[5] = '\0';

    // return ch;
    return str;
}


int main(int argc, char *argv[])
{
    char *p;
    p = fun();
    printf("p = %s\n",p);   // p = hello

    // 使用free函数释放空间
    free(p);
    // 防止野指针
    p = NULL;

    return 0;
}


realloc重新申请内存堆空间

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

void test1()
{
    char *p;
    p = (char *) malloc(100);
    printf("%p\n",p);

    // 在100个字节后面追加50个字节
    p = (char *)realloc(p,150);  // p指向的内存的新的大小为150个字节
    printf("%p\n",p);
}

void test2()
{
    char *p;
    p = (char *)malloc(100);
    printf("%p\n",p);

    // 想重新申请内存,新的大小为50个字节
    // p指向的内存的新的大小为50个字节,100个字节的后50个字节的存储空间就被释放
    p = (char*)realloc(p,50);
    printf("%p\n",p);
}


int main(int argc, char *argv[])
{
    test1();
    test2();

    return 0;
}



内存泄露

申请的内存,首地址丢了,找不到了,再也没法使用了,也没法释放了,这块内存就被泄露了。

#include <stdio.h>

int main()
{
    char *p;
    p = (char *)malloc(100);
    // 接下来就可以使用p指向的内存了

    p = "hello world";  // p指向别的地方了,保存字符串常量的首地址

    // 从此再也找不到你申请的100个字节了。则动态申请的100个字节就被泄露了

    return 0;
}


#include <stdio.h>

void fun()
{
    char *p;
    p = (char*)malloc(100);
    // 接下来 可以用p指向的内存了
	// ...
	
	//	free(p);  // 这是解决内存泄露的方法
}

int main()
{
    // 每调用一次 fun 泄露100个字节  因为fun函数没释放内存,也没返回内存地址,找不到这块堆区空间
    fun();
    fun();

	

    return 0;
}


字符串处理函数

  • 获取字符串长度函数
#include <stdio.h>
#include <string.h>

int main()
{
    // 使用strlen函数获取字符串的长度
    // strlen获取的字符串的长度遇到第一个\0结束
    char s1[100] = "hel\0lo";

    printf("s1_len = %d\n", strlen(s1));    // s1_len = 3
    printf("si_size = %d\n", sizeof(s1));   // si_size = 100

    char *s2 = "hello";

    printf("s2_len = %d\n", strlen(s2));    // s2_len = 5
    printf("s2_size = %d\n", sizeof(s2));   // s2_size = 4  32位系统里,不管指针变量是什么类型,都是占4个字节。

    return 0;
}

  • 字符串拷贝、追加、比较、查找、匹配函数

字符串拷贝

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


int main()
{
    // 使用strcpy函数拷贝字符串
    char s1[32] = "hello world";
    char s2[32] = "abcdefg";

    char *a;

    a = strcpy(s1,s2);               // 将s2字符串内容拷贝到s1   函数的返回值是目的内存的地址
    // 注意:使用strcpy函数的时候 需要确保s1的内存空间大于等于s2的  否则会出现内存污染

    printf("%s\n",a);         // abcdefg

    printf("s1 = %s\n", s1);    // s1 = abcdefg

    int i;
    for(i=0;i < 32; i++)
    {
        printf("[%c] - %d\n", s1[i], s1[i]);      // %c 输出字符   %d  输出字符的ascii值
        // [a] - 97
        // [b] - 98
        //  [c] - 99
        //  [d] - 100
        //  [e] - 101
        //  [f] - 102
        //  [g] - 103
        //  [

追加

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


int main()
{
    // 使用strcat函数追加字符串
    char s1[32] = "hello world";
    char s2[32] = "abcdef";

    // strcat是从s1的\0的位置开始追加,直到s2的第一个\0复制完毕后结束
    strcat(s1, s2);

    printf("s1 = %s\n", s1);   // s1 = hello worldabcdef
    return 0;
}


比较字符串内容是否一致

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


int main()
{
    // 使用strcmp函数比较两个字符串的内容是否一致
    // strcmp函数是逐个字符进行ascii值的比较, 返回值为1 说明s1>s2, 返回值为-1 说明s1<s2
    char s1[] = "aell";
    char s2[] = "g";

    int ret = strcmp(s1, s2);
    printf("%d\n", ret);

    // 使用strncmp函数比较两个字符串的前n个字符内容是否一致
    char s3[] = "hello";
    char s4[] = "hella";
    int ret1 = strncmp(s3, s4, 4);   // 比较前4个字符  等于0说明是一致的
    printf("%d\n", ret1);

    return 0;
}


查找字符在字符串中的位置 查不到返回NULL

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


int main()
{
    // 使用strchr函数在一个字符串中查找字符  从左边开始的找第一个匹配字符
    char s[] = "hel6lo wor6ld";
    // char *ret = strchr(s, '6');   // 这里使用字符或者ASCII码值都行
    char *ret = strchr(s, 54);
    if(ret == NULL)
    {
        printf("not found\n");
    }
    else {
        printf("in  %d\n", ret -s);
    }

    // 使用strrchr函数在一个字符串中查找字符  从右边开始的找第一个匹配字符


    return 0;
}



字符串匹配函数 使用strstr函数在一个字符串中查找另一个字符串

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


int main()
{
    // 字符串匹配函数  使用strstr函数在一个字符串中查找另一个字符串
    char s[] = "1234:4567:666:789:666:7777";

    // strstr查找的时候 查找的是第二个参数的第一个\0之前的内容 不包含第二个参数的\0
    char *ret = strstr(s, "666");

    printf("%p\n", s);     // 0060FE81
    printf("%p\n", ret);   // 0060FE8B
    printf("%d\n",ret - s);   // 10

    return 0;
}


  • 字符串转换数值

使用atoi将数字型字符串转化为整形数据

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

int main()
{
    // 使用atoi将数字型字符串转化为整形数据
    char s1[] = "7856";
    int ret1 = atoi(s1);

    printf("ret1 = %d\n", ret1);   //  ret1 = 7856

    // 使用atof将浮点型的字符串转化为浮点型数据
    char s2[] = "3.1415926";
    double ret2 = atof(s2);

    printf("ret2 = %lf\n", ret2);   // ret2 = 3.141593

    return 0;
}


  • 字符串切割函数
#include <stdio.h>
#include <string.h>

int main()
{
    // 使用strtok函数切割字符串

    char s[] = "111:2222:3333333:44444:55555555555";
    // char *s = "111:2222:3333333:44444:55555555555"; // 这里不能用char* 因为char *定义的字符串存储在字符常量区

    char *ret;

    // 第一次切割
    ret = strtok(s, ":");
    printf("ret = %s\n", ret);      // ret = 111

    // 后面所有的切割都要将strtok的第一个参数传NULL
    while ( ( ret = strtok(NULL, ":") ) != NULL ) {
        printf("ret00 = %s\n", ret);
    }
    // ret00 = 2222
    // ret00 = 3333333
    // ret00 = 44444
    // ret00 = 55555555555

    return 0;
}


  • 格式化字符串操作函数

#include <stdio.h>


// sprintf和sscanf的基本用法
void test1()
{
    char buf[20];
    int a, b, c;

    sprintf(buf, "%d:%d:%d", 2023, 10, 1);
    printf("buf= %s\n", buf);          // buf= 2023:10:1

    sscanf("2023:10:1", "%d:%d:%d", &a, &b, &c);
    printf("a=%d, b=%d, c=%d\n", a, b, c);    // a=2023, b=10, c=1
}

// sscanf高级用法
void test2()
{
    // 1、跳过数据:%*s 或者 %*d
    char buf1[20];
    sscanf("1234 5678", "%*d %s", buf1);
    printf("%s\n", buf1);      // 5678

    // 2、读指定宽度的数据:%[width]s
    char buf2[20];
    sscanf("12345678", "%4s ", buf2);
    printf("%s\n", buf2);      // 1234

    // 3、支持集合操作:只支持获取字符串
    // %[a-z] 表示匹配a到z中任意字符(尽可能多的匹配)
    // %[aBc] 匹配a、B、c中一员,贪婪性
    // %[^aFc] 匹配非a、F、c的任意字符,贪婪性
    // %[^a-z] 表示读取除a-z以外的所有字符
    char buf3[20];
    sscanf("agcd32DajfDdFF", "%[a-z]", buf3);
    printf("%s\n", buf3);     // agcd


}

int main()
{

    test1();
    test2();

    return 0;
}



const

修饰普通变量 代表只读的意思


#include <stdio.h>

// const 修饰全局变量

// 此时全局变量只能使用但是不能修改
// 如果直接拿全局变量修改值,编译直接报错
// 如果使用全局变量的地址去修改值,运行时程序异常结束
const int a = 100;
void tes1()
{
    printf("a = %d\n", a);    // a = 100

    // a = 666;
    // printf("a = %d\n", a);

    //    int *p = &a;
    //    *p = 888;
    //    printf("a = %d\n", a);
}


// const修饰普通局部变量

// 可以读取变量的值
// 不能直接通过变量进行修改值,编译报错
// 可以通过变量的地址修改值
void test2()
{
    const int b = 100;
    printf("b = %d\n", b);   // b = 100

    // b = 666;
    // printf("b = %d\n", b);

    int *p = &b;
    *p = 888;
    printf("b = %d\n", b);   // b = 888
}


// const修饰指针变量

// 1、如果const修饰指针变量的类型,无法通过指针变量修改地址里面的值
void test3()
{
    int c = 100;
    const int *p = &c;
    printf("*p = %d\n", *p);      // *p = 100

    c = 666;
    printf("*p = %d\n", *p);      // *p = 666

    // *p = 777;
    // printf("*p = %d\n", *p);

    int d = 888;
    p = &d;
    printf("*p = %d\n", *p);      // *p = 888
}

// 2、如果const修饰指针变量,无法修改指针变量保存的地址
void test4()
{
    int c = 100;
    int * const p = &c;
    printf("*p = %d\n", *p);      // *p = 100

    c = 666;
    printf("*p = %d\n", *p);      // *p = 666

    *p = 777;
    printf("*p = %d\n", *p);      // *p = 777

    int d = 888;
    // p = &d;
    // printf("*p = %d\n", *p);
}

int main()
{

    tes1();
    test2();
    test3();
    test4();

    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值