C/C++学习之C提高----函数调用模型、指针做函数参数、字符串的基本操作、一级指针内存模型建立

1.函数调用模型

这里写图片描述

这里写图片描述

这里写图片描述

2.画代码内存四区图

全局区代码测试
char * getstring1()
{
    char *p1 = "abcde";
    return p1;
}

char * getstring2()
{
    char *p2 = "abcde";
    return p2;
}


void main()
{
    int i= 0;

    //指针指向谁就把谁的地址赋给指针变量。
    char *p1 = getstring1();
    char *p2 = getstring2();
    char *******    p3 = NULL; //p3 是个变量

    //指针变量和它所执行的内存空间变量是两个不同的概念
    strcmp(p1, p2);

    system("pause");
}

这里写图片描述

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

//野指针产生的原因
//指针变量和它所指向的内存空间变量是两个不同的概念
//释放了指针所指的内存空间  但是指针变量本身没有重置成null
//造成释放的时候 通过if (p1 != NULL)

//避免方法: 1)定义指针的时候 初始化成nuLL 2)释放指针所指向的内存空间后,把指针重置成NULL。
void main()
{

    char  *p1 = NULL;
    p1 = (char *)malloc(100);
    if (p1 == NULL)
    {
        return ;
    }
    strcpy(p1, "11112222");

    printf("p1:%s \n", p1);

    if (p1 != NULL)
    {
        free(p1);
        p1 = NULL;
    }

    if (p1 != NULL)
    {
        free(p1);
    }

    printf("hello...\n");
    system("pause");
    return ;
}

这里写图片描述

3.向null地址处copy数据

  • 1.strcopy(NULL,”abcdefg”);
  • 2.向指定的内存空间copy数据,提示指定的值

(1)代码

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

void main()
{

    char *p1 = NULL;

    strcpy(p1, "abcdefg");
    printf("hello...\n");
    system("pause");
    return ;
}

(2)运行结果

这里写图片描述

4.不断改变指针指向

(1)代码

#define  _CRT_SECURE_NO_WARNINGS 
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void main()
{
    char    buf[128]; //c可以在栈上分配内存
    int     i; 
    int     j = 0;

    char    *p2 = NULL; 

    char *p1 = NULL;

    p1 = &buf[0]; //不断的修改p1的值 相当于 不断改变指针的指向
    p1 = &buf[1];
    p1 = &buf[2];

    for (i=0; i<10; i++)
    {
        p1 = buf[i];
    }

    p2 = (char *)malloc(100);
    strcpy(p2, "abcdefg1212333333333311");

    for (i=0; i<10; i++)
    {
        p1 = p2+i;
        printf("%c ", *p1);
    }

    printf("hello...\n");
    system("pause");
    return ;
}

(2)四区图

这里写图片描述

(3)运行结果

这里写图片描述

5.直接和间接赋值

(1)代码

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

int  getFileLen(int *p)
{
    *p = 41;  //  p的值是a的地址 *a的地址间接修改a的值 
    //在被调用函数里面 通过形参 去 间接的修改 实参的值...
}

//return 只能返回一个结果
int  getFileLen2()
{
    int a = 100;  
    return a;
}

//形参的属性
int  getFileLen3(int b)
{
    b = 100;
}


//1级指针的技术推演
void main()
{
    int a = 10;  //条件1  定义了两个变量(实参 另外一个变量是形参p)
    int *p = NULL;

    //修改a的值
    a = 20; //直接修改

    p = &a;  //条件2 建立关联

    *p = 30; //p的值是a的地址 *就像一把钥匙 通过地址 找到一块内存空间 求间接的修改了a的值
    printf("a: %d \n", a);

    {
        *p = 40;  //  p的值是a的地址 *a的地址间接修改a的值  //条件3 *p
        printf("a: %d \n", a);
    }

    getFileLen(&a); //建立关联: 把实参取地址 传递给 形参
    printf("getFileLen后 a: %d \n", a);
    getFileLen3(a);
    printf("getFileLen3后 a: %d \n", a);//发现并没有修改a的值

    printf("hello...\n");
    system("pause");
    return ;
}

(2)四区图

这里写图片描述

(3)运行结果

这里写图片描述

6.一级指针到二级指针

(1)代码

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

void getMem(char **p2)
{
    *p2 = 400; //间接赋值  p2是p1的地址
}

void main()
{
    char *p1 = NULL;

    char **p2 = NULL;

    p1 = 0x11;
    p2 = 0x22;

    //直接修改p1的值

    p1 = 0x111;

    //间接修改p1的值
    p2 = &p1; 

    *p2 = 100; //间接赋值  p2是p1的地址

    printf("p1:%d \n", p1);

    {
        *p2 = 200; //间接赋值  p2是p1的地址
        printf("p1:%d \n", p1);
    }

    getMem(&p1);    
    printf("p1:%d \n", p1);

    system("pause");
    return ;
}

(2)运行结果

这里写图片描述

7.指针做函数参数

  • 函数调用时,形参传给实参,用实参取地址,传给形参,在被调用函数里面用*p来改变实参,把运算结果传出来。
  • 这便是指针作为函数参数的精髓

(1)代码

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

//指针做函数参数
int  getMem3(char **myp1, int *mylen1,  char **myp2, int *mylen2)
{
    int     ret = 0;
    char    *tmp1, *tmp2;

    tmp1 = (char *)malloc(100);
    strcpy(tmp1, "1132233");

    //间接赋值 
    *mylen1 = strlen(tmp1);  //1级指针
    *myp1 = tmp1; //2级指针的间接赋值

    tmp2 = (char *)malloc(200);
    strcpy(tmp2, "aaaaavbdddddddd");

    *mylen2 = strlen(tmp2);  //1级指针
    *myp2 = tmp2; //2级指针的间接赋值


    return ret;
}

int  main()
{
    int     ret = 0;
    char    *p1 = NULL;
    int     len1 = 0;
    char    *p2 = NULL;
    int     len2 = 0; 

    ret = getMem3(&p1, &len1, &p2, &len2);
    if (ret != 0)
    {
        printf("func getMem3() err:%d \n", ret);
        return ret;
    }
    printf("p1:%s \n", p1);
    printf("p2:%s \n", p2);

    if (p1 != NULL)//释放空间
    {
        free(p1);
        p1 = NULL;
    }
    if (p2 != NULL)//释放空间
    {
        free(p2);
        p2 = NULL;
    }

    system("pause");
    return ret;
}

(2)运行结果

这里写图片描述

8.间接赋值成立的三个条件

  • 条件1:定义1个变量(实参)定义1个变量(形参)
  • 条件2:建立关联:把实参取地址传给形参
  • 条件3:*形参去间接地的修改了实参的值。

9.字符串的基本操作

    1. C语言的字符串 以零结尾的字符串
    1. 在C语言中没有字符串类型 通过字符数组 来模拟字符串
    1. 字符串的内存分配 堆上 栈上 全局区 (很重要)

(1)字符数组的初始化

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

//字符数组 初始化
void main()
{

    //1 指定长度  
    char buf2[100] = {'a', 'b', 'c', 'd'};  
    //1-1char buf3[2] = {'a', 'b', 'c', 'd'}; //如果初始化的个数大于内存的个数 编译错误
    //1-22//后面的buf2[4]-buf2[99] 0


    //2 不指定长度  C编译器会自动帮程序员 求元素的个数
    char buf1[] = {'a', 'b', 'c', 'd'};  //buf1是一个数组 不是一个以0结尾的字符串

    printf("buf2: %s \n", buf2);

    printf("buf2[88]:%d \n", buf2[88]);

    printf("hello....\n");
    system("pause");

    return ;
}

这里写图片描述

(2)用字符串来初始化字符数组

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

//用字符串来初始化字符数组
//strlen() 长度 不包括0
//sizeof() 内存块的大小
void main()
{
    int size = 0;
    char buf3[] = "abcd"; // buf3 作为字符数组,应该是5个字节;作为字符串 应该4个字节

    int len = strlen(buf3);
    printf("buf3字符的长度:%d \n", len); //4

    //buf3 作为数组 数组是一种数据类型 本质(固定小大内存块的别名)
    size = sizeof(buf3); //
    printf("buf3数组所占内存空间大小:%d \n", size); //5

    printf("hello....\n");

    {
        char buf4[128] = "abcd"; // buf
        printf("buf4[100]:%d \n", buf4[100]);
    }
    system("pause");
    return ;
}

这里写图片描述

(3)通过数组下标和指针操作字符数组

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

//通过数组下标 和 指针
void main()
{
    int     i = 0;
    char    *p = NULL;
    char buf5[128] = "abcdefg"; // buf5

    for (i=0; i<strlen(buf5); i++)
    {
        printf("%c ", buf5[i]); 
    }

    p = buf5; //buf5 代表数组首元素的地址

    for (i=0; i<strlen(buf5); i++)
    {
        p = p +i;
        printf("%c ", *p ) ;
    }

    printf("hello....\n");
    system("pause");
}

(4)[ ]和*的推导过程

  • buf[i] ===> buf[0+i]; ==> *(buf+i);
  • []的本质:和*p 是一样 ,只不过是符合程序员的阅读习惯
  • buf 是一个指针,只读的常量;
  • buf 是一个常量指针,析构内存的时候,保证buf所指向的内存空间安全释放

10.一级指针内存模型建立

(1)代码

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

void main61()
{
    char buf[20]= "aaaa"; //定义并且初始化
    char buf2[] = "bbbb";
    char *p1 = "111111";
    char *p2 = malloc(100); 
    strcpy(p2, "3333");

    system("pause");
    return ;
}

(2)内存模型图

这里写图片描述

10.字符串做函数参数

(1)字符串的复制

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

void main()
{
    char a[] = "i am a student";
    char b[64];
    int  i = 0;

    for (i=0; *(a+i) != '\0'; i++)
    {
        *(b+i) = *(a+i);
    }

    //0没有copy到b的buf中.

    b[i] = '\0'; //重要
    printf("a:%s \n", a);
    printf("b:%s \n", b);

    system("pause");
    return ;
}

这里写图片描述

(2)字符串copy函数

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

//from形参 形参to 的值 不停的在变化....
//不断的修改了from和to的指向
void copy_str(char *from, char *to)
{
    for (; *from!='\0'; from++, to++)
    {
         *to = *from;
    }
    *to = '\0';

    return ;
}
void main()
{
    char *from = "abcdefg";
    char buf2[100];
    copy_str(from,buf2);

    printf("buf2:%s \n",buf2);
    system("pause");
    return ;
}

这里写图片描述

这里写图片描述

(3)copy_str()演变

//1.
void copy_str(char *from, char *to)
{
    for (; *from!='\0';)
    {
        *to++ = *from++;  //  先 *to = *from;  再from++, to++ 
    }
    *to = '\0'; //

    return ;
}

//2.
void copy_str(char *from, char *to)
{
    while( (*to = *from) != '\0' )
    {
        from ++; 
        to ++;
    }
}

//3.
void copy_str(char *from , char *to)
{
    while ( (*to++ = *from++) != '\0')
    {
        ;
    }
}

//4.
void copy_str(char *from , char *to)
{
    while ( (*to++ = *from++) )
    {
        ;
    }
}

//5.重点***
//不要轻易改变形参的值, 要引入一个辅助的指针变量. 把形参给接过来.....
int copy_str26_good(char *from , char *to)
{
    char *tmpfrom = from;
    char *tmpto = to;
    if ( from == NULL || to == NULL)
    {
        return -1;
    }

    while ( *tmpto++ = *tmpfrom++ ) ;  //空语句

    printf("from:%s \n", from); 
}

11.项目开发字符串模型

  • 要求:
  • char *p = “abcd111122abcd3333322abcd3333322qqq”;
  • 求字符串p中 abcd出现的次数

(1)使用strstr(str, str2)函数配合do_while()

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

void main()
{
    int ncount = 0;

    //初始化 让p指针达到查找的条件
    char *p = "11abcd111122abcd3333322abcd3333322qqq";


    do
    {
        p = strstr(p, "abcd");
        if (p != NULL)
        {
            ncount++; //
            p = p + strlen("abcd"); //指针达到下次查找的条件
        }
        else
        {
            break;
        }
    } while (*p != '\0');

    printf("ncount:%d \n", ncount);

    system("pause");
    return;
}

这里写图片描述

(2)使用strstr(str, str2)函数配合while()

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

void main()
{
    int ncount = 0;

    //初始化 让p指针达到查找的条件
    char *p = "2abcd3333322qqqabcd";
    while (p = strstr(p, "abcd"))
    {
        ncount++;
        p = p + strlen("abcd"); //让p指针达到查找的条件
        if (*p == '\0')
        {
            break;
        }
    }
    printf("ncount:%d \n", ncount);

    system("pause");
}

这里写图片描述

(3)自定义函数完成

  • 请自定义函数接口,完成上述需求
  • 自定义的业务函数 和 main函数必须分开
代码
#define  _CRT_SECURE_NO_WARNINGS 
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int getCount(char *mystr /*in*/, char *sub /*in*/, int *ncount)
{
    int ret = 0;
    int tmpCount = 0;
    //初始化 让p指针达到查找的条件
    char *p = mystr; //不要轻易改变形参的值

    if (mystr == NULL || sub == NULL || ncount == NULL)
    {
        ret = -1;
        printf("func getCount() err:%d (mystr==NULL || sub==NULL ||ncount==NULL) \n", ret);
        return ret;
    }

    do
    {
        p = strstr(p, sub);
        if (p != NULL)
        {
            tmpCount++; 
            p = p + strlen(sub); //指针达到下次查找的条件
        }
        else
        {
            break;
        }
    } while (*p != '\0');

    *ncount = tmpCount; //间接赋值是指针存在的最大意义
    return ret;
}

int main()
{
    int ret = 0;
    char *p = "abcd111122abcd3333322abcd3333322qqq";
    int count = 0;
    char sub[] = "abcd";

    ret = getCount(p, sub, &count);
    if (ret != 0)
    {
        printf("func getCount() err:%d \n", ret);
        return ret;
    }

    printf("count:%d \n", count);
    system("pause");
}
运行结果

这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值