C语言 13.

1.calloc 和 realloc

1.1calloc 和malloc 都是在堆区分配内存

1.2与malloc不同的是,calloc会将空间初始化为0

1.3calloc(个数,大小)

1.4realloc 重新分配内存

1.4.1如果重新分配的内存比原来大,那么不会初始化新空间为0

1.4.2先看后续空间,如果足够,那么直接扩展

1.4.3如果后续空闲空间不足,那么申请足够大的空间,将原有数据拷贝到新空间下,释放掉原有空间,将新空间的首地址返回

1.4.4如果重新分配的内存比原来小,那么释放后序空间,只有权限操作申请空间


//calloc
void test01()
{
    //int * p = malloc(sizeof(int)* 10);   //  没有初始化操作,打印出来会是乱码
    int * p = calloc(10, sizeof(int)); //calloc 分配在堆区,与malloc不同的是 calloc会初始化数据为0
    for (int i = 0; i < 10;i++)
    {
        printf("%d\n", p[i]);
    }
    if ( p != NULL)
    {
        free(p);
        p = NULL;
    }
}
//realloc  重新分配内存
void test02()
{
    int * p = malloc(sizeof(int)* 10);    // 先分配一个小内存
    for (int i = 0; i < 10;i++)
    {
        p[i] = i + 100;
    }
    for (int i = 0; i < 10; i++)
    {
        printf("%d\n", p[i]);
    }
    printf("%d\n", p);
    //如果重新分配的内存比原来大,那么不会初始化新空间为0
    p = realloc(p, sizeof(int)* 20)    // P代表首地址,第二个参数代表大小,返回一个新的地址
    printf("%d\n", p);
    for (int i = 0; i < 20; i++)
    {
        printf("%d\n", p[i]);
    }
    //如果重新分配的内存比原来小,那么释放后序空间,只有权限操作申请空间
    p = realloc(p, sizeof(int)* 5);
    printf("%d\n", p);
    printf("%d\n", p[0]);
    printf("%d\n", p[5]);      // 这里是乱码
}

在这里插入图片描述

2.sscanf的使用

符号作用
%*s或%*d跳过数据
%[width]s读指定宽度的数据
%[a-z]匹配a到z中任意字符(尽可能多的匹配)
%[aBc]匹配a、B、c中一员,贪婪性
%[^a]匹配非a的任意字符,贪婪性
%[^a-z]表示读取除a-z以外的所有字符

2.1练习

2.1.1将 ip 分别截取到 num1 到 num4中

2.1.2将 123456#zhangtao@abcde 中截取中间的zhangtao有效数据


#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//1、%*s或%*d    跳过数据
void test01()
{
    char * str = "12345abcde";
    char buf[1024] = { 0 };
    sscanf(str, "%*d%s", buf);    // 这一步做操作,不输出数据
    printf("%s\n", buf);      //  abcde 
}
void test02()
{
    char * str = "abcde12345"; //忽略遇到空格或者 \t 代表忽略结束
    char buf[1024] = { 0 };
    sscanf(str, "%*[a-z]%s", buf);     // 把a-z之间的数字忽略掉,然后匹配输出
    //sscanf(str, "%*s%s", buf);        // 什么都没有
    printf("%s\n", buf);
}
//%[width]s    读指定宽度的数据
void test03()
{
    char * str = "12345abcde";
    char buf[1024] = { 0 };
    sscanf(str, "%6s", buf);   // 12345a
    printf("%s\n", buf);
}
//%[a-z]    匹配a到z中任意字符(尽可能多的匹配)
void test04()
{
    char * str = "12345abcdeaaa";
    char buf[1024] = { 0 };
    sscanf(str,"%*d%[a-c]", buf); //只要匹配失败,那么就不继续匹配了
    printf("%s\n", buf);    // abc
}
void test05()
{
    char * str = "12345abcdeaaa";
    char buf[1024] = { 0 };
    sscanf(str, "%[0-9]", buf); //只要匹配失败,那么就不继续匹配了
    printf("%s\n", buf);    // 12345
}
//%[aBc]    匹配a、B、c中一员,贪婪性(只匹配这几个,不是这几个都不需要匹配)
void test06()
{
    char * str = "abcCdef";
    char buf[1024] = { 0 };
    sscanf(str, "%[abC]", buf); //只要匹配失败,那么就不继续匹配了
    printf("%s\n", buf);  // ab
}
//%[^a]     匹配非a的任意字符,贪婪性
void test07()
{
    char * str = "abcCdef";
    char buf[1024] = { 0 };
    sscanf(str, "%[^C]", buf); 
    printf("%s\n", buf);         // abc
}
//%[^a-z]    表示读取除a-z以外的所有字符
void test08()
{
    char * str = "abcCdef123456";
    char buf[1024] = { 0 };
    sscanf(str, "%[^0-9]", buf);   // abcCdef
    printf("%s\n", buf);
}
//练习1  把ip地址里的数字都单独拿出来
void test09()
{
    char * ip = "127.0.0.1";
    int num1 = 0;
    int num2 = 0;
    int num3 = 0;
    int num4 = 0;
    sscanf(ip, "%d.%d.%d.%d", &num1, &num2, &num3, &num4);
    printf("%d\n", num1);
    printf("%d\n", num2);
    printf("%d\n", num3);
    printf("%d\n", num4);
}
//练习2   输出#和@之间的有效字符
void test10()
{
    char * str = "abcdef#zhangtao@123456";
    char buf[1024] = { 0 };
    sscanf(str, "%*[^#]#%[^@]", buf);   // * 表示忽略  [^#]忽略#之外的符号(到#时这个忽略停止工作)  #:忽略#    %[^@]匹配@符号之外的符号(到@时停止工作,后面的也不再匹配)
           //   %*[^#]%*#  忽略     %[^@]匹配
    printf("%s\n", buf);    //    zhangtao
}
//1.    已给定字符串为: helloworld@itcast.cn,请编码实现helloworld输出和itcast.cn输出。
void test11()
{
    char * str = "helloworld@itcast.cn";
    char buf1[1024] = { 0 };
    char buf2[1024] = { 0 };
    sscanf(str, "%[a-z]%*[@]%s", buf1, buf2);   // 两个匹配之间夹了一个忽略
    printf("%s\n", buf1);
    printf("%s\n", buf2);
}

3.查找子串

3.1实现mystrstr 自己查找子串功能
在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
/*
    算法优化
    memcmp(str , subStr ,3 ) == 0;    //内存的对比机制
*/
int myStrstr(char * str , char * subStr)
{
    int num = 0;
    while (*str != '\0')
    {
        if (*str != *subStr)
        {
            num++;
            str++;
            continue;
        }
        //创建两个临时指针 做二次对比
        char * tmpStr = str;
        char * tmpSubstr = subStr;
        while (*tmpSubstr != '\0')
        {
            if (*tmpStr != *tmpSubstr)
            {
                //匹配失败
                num++;
                str++;
                break;
            }
            tmpStr++;
            tmpSubstr++;
        }
        if (*tmpSubstr == '\0')
        {
            //匹配成功
            return num;
        }
    }
    return -1;
}
void test01()
{
    char * str = "abdnfcdefgdfasdfaf";
    int ret = myStrstr(str, "dnf");
    if ( ret != -1)
    {
        printf("找到了子串,位置为:%d\n", ret);
    }
    else
    {
        printf("未找到子串\n");
    }
}
int main(){
    test01();
    system("pause");
    return EXIT_SUCCESS;
}

4指针的易错点

4.1越界

4.2指针叠加会不断改变指针指向

4.3返回局部变量地址

4.4同一块内存释放多次(不可以释放野指针)


void test01()
{
    char * p = malloc(sizeof(char)* 64);
    char * pp = p; //通过创建临时指针操作内存,防止出错
    for (int i = 0; i < 10;i++)
    {
        *pp = i + 97;  // 原本是*p = i+97
        printf("%c\n", *pp);
        pp++; //更改指针位置,释放出错
    }
    if (p!= NULL)
    {
        free(p);
    }
}

5const使用场景

5.1const使用 修饰形参 防止误操作



struct Person
{
    char name[64]; // 0 ~ 63
    int age; // 64 ~ 67
    int Id;  // 68 ~ 71
    double score; // 72 ~79
};
//将struct Person p 改为 struct Person * p  节省资源,但是指针容易误操作
//const使用  修饰形参 防止误操作
void showPerson(const struct Person *p)   // 这个函数目的只是为了打印,不能有数字的更改
{
    // 如果使用 struct Person p  值传递,不会更改本体,但是每次都要占用很大的内存
    //p.age = 100;      
    //p->age = 100;   // 指针访问指针用->
    //printf("姓名: %s  年龄: %d  学号 %d  分数 %f\n", p.name, p.age, p.Id, p.score);
    printf("姓名: %s  年龄: %d  学号 %d  分数 %f\n", p->name, p->age, p->Id, p->score);
}

6二级指针做函数参数的输入输出特性

6.1二级指针做函数参数的输入特性

6.1.1创建在堆区

6.1.2创建在栈区

6.2二级指针做函数参数的输出特性

6.2.1被调函数分配内存,主调函数使用
在这里插入图片描述
在这里插入图片描述

void printArray(int ** pArray , int len)
{
    for (int i = 0; i < len;i++)
    {
        printf("%d\n", *pArray[i]);
    }
}
void test01()
{
    //创建在堆区
    int ** pArray = malloc(sizeof(int *)* 5);
    //在栈上创建5个数据
    int a1 = 10;
    int a2 = 20;
    int a3 = 30;
    int a4 = 40;
    int a5 = 50;
    pArray[0] = &a1;
    pArray[1] = &a2;
    pArray[2] = &a3;
    pArray[3] = &a4;
    pArray[4] = &a5;
    //打印数组
    printArray(pArray, 5);
    //释放堆区数据
    if (pArray != NULL)
    {
        free(pArray);
        pArray = NULL;
    }
}
void freeSpace(int **pArray , int len)
{
    for (int i = 0; i < len;i++)
    {
        free(pArray[i]);
        pArray[i] = NULL;
    }
}
void test02()
{
    //创建在栈区
    int * pArray[5];
    for (int i = 0; i < 5;i++)
    {
        pArray[i] = malloc(4);
        *(pArray[i]) = 10 + i;
    }
    printArray(pArray, 5);
    //释放堆区
    freeSpace(pArray,5);
}
```c
void allocateSpace(int ** p)
{
    int *  temp = malloc(sizeof(int)* 10);
    for (int i = 0; i < 10;i++)
    {
        temp[i] = 100 + i;
    }
    *p = temp;
}
void printArray(int ** pArray, int len)
{
    for (int i = 0; i < len;i++)
    {
        printf("%d\n", (*pArray)[i]);
    }
}
void freeSpace(int ** pArray)
{
    if (*pArray != NULL)
    {
        free(*pArray);
        *pArray = NULL;
    }
}
void test01()
{
    int * p = NULL;
    allocateSpace(&p);
    printArray(&p, 5);
    freeSpace(&p, 5);
    
    if (p == NULL)
    {
        printf("空指针\n");
    }
    else
    {
        printf("野指针\n");
    }
}

7二级指针练习-文件操作

7.1读取配置文件信息,并且将信息存放到 数组中

7.2注意: 释放堆区,关闭文件



//获取有效行数
int getFileLines(FILE * pFile)
{
    if (pFile == NULL)
    {
        return -1;
    }
    char buf[1024] = { 0 };
    int lines = 0;
    while (fgets(buf,1024,pFile) != NULL)
    {
        //printf("%s", buf);
        lines++;
    }
    //将文件光标置首
    fseek(pFile, 0, SEEK_SET);
    return lines;
}
//读取数据放入到pArray中
void readFileData(FILE * pFile, int len, char ** pArray)
{
    if (pFile == NULL)
    {
        return;
    }
    if (len <= 0 )
    {
        return;
    }
    if ( pArray ==NULL)
    {
        return;
    }
    char buf[1024] = { 0 };
    int index = 0;
    while (fgets(buf, 1024, pFile) != NULL)
    {
        /*
        aaaaaaaaaa
        bbbb
        cccccc
        */
        int currentLen = strlen(buf) +1 ;
        char * currentStrP = malloc(sizeof(char)* currentLen);
        strcpy(currentStrP, buf);
        pArray[index++] = currentStrP;
        memset(buf, 0, 1024);
    }
}
void showFileData(char ** pArray, int len)
{
    for (int i = 0; i < len;i++)
    {
        printf("%d行的数据为 %s", i + 1, pArray[i]);
    }
    
}
void test01()
{
    //打开文件
    FILE * pFile =    fopen("./test.txt", "r");
    if (pFile == NULL)
    {
        printf("文件打开失败\n");
        return;
    }
    //统计有效行数
    int len =  getFileLines(pFile);
    //printf("文件的有效行数为:%d\n", len);
    char ** pArray =  malloc(sizeof(char *)* len);
    //读取文件中的数据并且放入到 pArray中
    readFileData(pFile, len, pArray);
    //读取数据
    showFileData(pArray , len);
    //释放堆区内容
    for (int i = 0; i < len; i++)
    {
        if (pArray[i] != NULL)
        {
            free(pArray[i]);
            pArray[i] = NULL;
        }
    }
    free(pArray);
    pArray = NULL;
    //关闭文件
    fclose(pFile);
}

8位运算

8.1按位取反 ~ 0变1 1 变0

8.2按位与 & 全1为1 一0为0

8.3按位或 | 全0为0 一1为1

8.4按位异或 ^ 相同为0不同为1



/按位取反 ~
void test01()
{
    int num = 2;
    // 010 取反
    // 101 源码
    //计算机用补码方式存数据  110 + 1      =  111
    printf("~num = %d\n", ~num); // -3
}
//按位与 &
void test02()
{
    int num = 123;
    if (  (num & 1 ) == 1 )
    {
        printf("num为奇数\n");
    }
    else
    {
        printf("num为偶数\n");
    }
}
//按位或 |
void test03()
{
    int num1 = 5;
    int num2 = 3;
    printf("num1 | num2 =  %d\n", num1 | num2); // 7
}
//按位异或  ^
void test04()
{
    int num1 = 5;
    int num2 = 9;
    /*int tmp = num1;
    num1 = num2;
    num2 = tmp;*/
    num1 = num1 ^ num2;
    num2 = num1 ^ num2;
    num1 = num1 ^ num2;
    //num1 = num1 + num2;
    //num2 = num1 - num2;
    //num1 = num1 - num2;
    printf("num1 = %d\n", num1);
    printf("num2 = %d\n", num2);
}
//左移运算 << 
void test05()
{
    int num = 20;  // 20 * 2 ^ 2;
    printf("%d\n", num <<= 2);
}
//右移运算 >>
void test06()
{
    int num = 20;  // 20 / 2
    printf("%d\n", num >>= 1);
}

9位移运算

9.1左移运算 << X 乘以2 ^ X

9.2右移运算 >> X 除以 2 ^X

9.2.1有些机器用0填充高位

9.2.2有些机器用1填充高位

9.2.3如果是无符号,都是用0填充

在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值