• C博客作业05--指针


    0.展示PTA总分

    1.本章学习总结

    1.1 指针定义、指针相关运算、指针做函数参数。

    指针定义

    指针指向的是一片内存地址:
    一般用定义数据类型的符号 和‘*’ 来定义指针

    int *p = &a;//定义指针p,取地址a 让p指向a。
    
    

    指针相关运算

    • 指针变量加/减一个整数

    例如:p++,p--,p+i等。
    C语言与 C++语言规定,一个 指针变量加/减一个 整数是将该指针变量的原值(是一个地址)和它指向的变量所占用的内存单元 字节数相加或相减。这样就保证了p+i指向p下面的第i个元素。
    如p+i代表这样的地址计算:p+i*d,其中d为p所指向的 变量单元所占用的 字节数。
    指针变量赋值
    C语言与C++语言规定,可以将一个 变量或一个函数的入口地址赋值给相应的指针变量。
    例如(假设p是相应的指针):
    p=&a;
    p=max;(max为已经定义的函数)

    • 指针变量相减

    如果两个 指针变量指向同一个 数组的元素,则两个指针变量之差是两个指针之间的元素个数。
    注意, 指针变量相加无实际意义。

    • 指针变量比较

    如果两个指针变量指向同一个数组的元素,则可以进行比较。指向前面元素的 指针变量小于指向后面元素的指针变量。

    指针做函数参数

    因为指针指向的是一片内存空间,所以用指针作为函数的参数,在函数体中,指针指向的形参的数改变了,那么指针指向的
    那片内存空间的值也会随之改变,所以指针可用于需要函数体传回多个值的时候使用。

    #include<stdio.h>
    void fun(int* x)
    {
    	*x = 3;//此时a那片内存的值为3,即使函数fun结束,a的值也不会消失
    }
    int main()
    {
    	int a;
    	int* p = &a;
    	fun(&a);//也可以直接传入指向a的指针,即传入一个地址:
           // fun(p);
    	return 0;
    }
    

    1.2 字符指针

    1.2.1指针如何指向字符串

    字符串可以由一个指针指向

    const char *p = "hellow";
    
    

    第一种直接用指针指向的无法改变其中的字符。
    或者一个数组存放,指针指向该数组

    char a[] = "hellow";
    char *p = a;
    

    用数组赋值的能更改其中的字符

    1.2.2字符串相关函数及函数代码原型的理解

    • strcpy
    char *strcpy(char *strDest, const char *strSrc)
    {
    baichar *r = strDest;
    while(*strDest++=*strSrc++);//把strSrc复制给strDest
    *strDest = 0;
    return r;
    }
    
    • strlen
    int strlen(const char* str)
    
    {
        if (NULL == str)
            throw"Invalid Argument!";
        int len;
        for (len = 0; *str&&*str != '
    '; str++)//算出字符串的长度
            len++;
        return len;
    }
    
    • strcat
    char *strcat(char *strDest, const char *strScr) 
    {
        char * address = strDest;
        if(!strDest||!strScr) return NULL;//防止传入空指针    
        while(*strDest)      
        {            
           strDest++;      //遍历字符串直到NULL  
        }            
        while(*strDest++ = *strScr++) //将strScr字符串连接到strDest之后
        {
           NULL;        
        }            
    return address;        
    }
    
    • strcmp
    int strcmp( const  char* src,const  char* dst)
    {
        int  ret = 0;
    
        while (!(ret = *(unsigned  char*)src - *(unsigned  char*)dst) && *dst)//逐个比较相对应的字符串的字符的大小
            ++src, ++dst;
    
        if (ret < 0)
            ret = -1;
        else  if (ret > 0)
            ret = 1;
    
        return(ret);
    }
    

    1.2.3字符串相关函数用法



    1.3 指针做函数返回值

    int *p()
    {
    reutrn p;//返回地址p
    }
    

    注意:
    1.如果p在函数中作了位运算,则返回的是该指针做了位运算的地址所以,
    一般需要在开始时定义一个指针指向p的首地址,然后返回该新定义的指针。
    2.返回的指针所指的内容的生存周期因为全局变量,如果在函数中定义了一片内容,
    然后返回指向该内容的指针则会报错。
    3.返回的指针需要作为判断时,也可返回NULL

    1.4 动态内存分配

    1.4.1为什么要动态内存分配

    • 要用一片连续的内存,如数组时,则可以用多少申请多少,不需要一开始把数组定义很大,占用多余的空间。
    • 在函数中申请可延长该数据的生存周期,直到程序结束或者free。

    1.4.2堆区和栈区区别

    1、栈区(stack)
    由编译器自动分配释放 ,存放函数的参数值,局部变量的值等,内存的分配是连续的,类似于平时我们所说的栈,如果还不清楚,那么就把它想成数组,它的内存分配是连续分配的,
    即,所分配的内存是在一块连续的内存区域内.当我们声明变量时,那么编译器会自动接着当前栈区的结尾来分配内存.

    2、堆区(heap)
    一般由程序员分配释放, 若程序员不释放,程序结束时可能由操作系统回收.类似于链表,在内存中的分布不是连续的,它们是不同区域的内存块通过指针链接起来的.
    一旦某一节点从链中断开,我们要人为的把所断开的节点从内存中释放.

    1.4.3动态内存分配相关函数及用法

    头文件 #include<stdlib.h>

    +malloc

    void * malloc (size_t size);

    malloc的使用比较直接,一个成功的malloc调用返回分配的size大小的内存的指针。失败时返回NULL并将错误代码置为ENOMEM。
    教材中经常出现的用法是将malloc返回的void指针进行强制内存转换然后赋给内存指针,其实是不必要的,在赋值时C语言是可以将void类型指针自动转换成对应的指针的。

    • calloc

    void * calloc (size_t nr, size_t size);

    calloc可以分配nr个size大小的内存空间,一般用于一组struct结构体的分配。
    那么calloc和malloc有什么区别呢?抛开nr参数不谈(malloc也可以将参数设置为nr*size达到一样的效果),
    最关键的区别是malloc分配的内存是不保证初始化的,而calloc会将分配的内存都初始化为0.

    +relloc

    void * realloc (void *ptr, size_t size);

    realloc函数将ptr指向的内存空间重新分配大小为size并返回新的内存首地址。具体的实现,函数首先会尝试直接在已经分配的内存后进行padding,如果空间足够那么还是返回原来的地址,
    如果不够,则会寻找新的空间并malloc size个字节,之后再将原先的内容“搬家”到新的内存地址,所以函数的返回值可能和原指针相同,也可能不同。
    另外,size参数如果是0,则该函数和free效果相同。如果ptr是NULL,函数的效果和malloc相同~

    注意用完这片内存后用free释放

    void free (void *ptr);

    释放前三个函数申请的内存空间。关于free最经典的问题就是内存泄露(memory leak)。所以,使用前三个分配函数分配的内存一定要记得free掉。

    1.4.4 举例为多个字符串做动态内存要如何分配

    char (*p)[10]
    p = (char(*)[10])calloc(n,sizeof(char[10]))
    char *a[10]
    a = (char*)calloc(n,sizeof(char))
    
    

    1.5 指针数组及其应用

    • 指针数组:用于存放字符指针的数组,仅用来存放指针,所以它指向的每个字符串的首地址均可以改变,
      由于指针指向一个地址,所以字符串的最大长度可以改变
    char *p[n]//n为行的数量
    
    • 二维数组:二维数组本质上是两个一维数组的合成,定义时就已经分配给二维数组空间。

    1.6 二级指针

    即指向一个一级指针的地址指针

    int **p;
    int *a;
    int n;
    p = &a;//二级指针p指向一级指针a
    a = &n;//一级指针a指向数n,则p最终也指向n的内容
    

    1.7 行指针、列指针

    行指针

    等同于int (*p)[3]
    则a为一个行指针,即a指向一个行的首地址,不指向其中的具体内容
    可以用a来寻址各行的内容
    或者移动到下一行p++

    列指针

    列指针与一个一级指针类似
    即所指的是具体的内容
    int a[3][3]
    int *p =a[0]

    2.PTA实验作业

    2.1 7-5 删除字符串中的子串

    2.1.1 伪代码

    定义s和删除的del字符串
    while(strstr(s,del)!=NULL)//重复寻找直至没有需要删除的字符串
      计算此时两个字符串的长度
      strcpy(temp,strstr(s,del))//将重复字符包括后面的字符串复制给temp
      计算temp的长度
      strcpy(s+len_s-loc,temp+len_del)/*s+s的长度到最后一个字符减去loc
      则到要删除的字符串的首地址,将temp+删除字符的长度,则为删去字符串后
      的字符串,复制到原字符串后面。*/
    end while
    

    2.1.2 代码截图

    2.1.3 找一份同学代码(尽量找思路和自己差距较大同学代码)比较,说明各自代码特点


    骆锟宏同学的代码是找到了子串然后进到函数进行一次删除,使指针的指向更清晰。

    2.2 合并2个有序数组

    2.2.1 伪代码

    定义用来排序的数组c//用选择法或者冒泡法会超时
    for 0 to m
    c[a[i]]++
    if(a[i]>max)a[i] = max 寻找最大值,在遍历c时有个上限
    end if
    end for
    for 0 to n
    和第一个for循环相同 遍历数组b,寻找最大值
    for 0 to max
    if(c[i]>0)
    for 0 to c[i]
    a[j] = i//将排序好的数存入a数组
    end if
    end for
    end for

    2.2.2 代码截图

    2.2.3 找一份同学代码(尽量找思路和自己差距较大同学代码)比较,说明各自代码特点。

    林进源同学的代码是边比较边排序,少了许多循环,占用更少的内存,从最后面往前排序,也不会使原来的还未排序数被覆盖。

    2.3 说反话-加强版

    2.3.1 伪代码

    定义str的长度len,i = len -1
    while
      while(str[i]不为空格及i>=0时)
      i-- count ++
      end while
      if(count >=1)
        for 0 to count
        使a存放str的元素//将str的元素倒放过来
        end for 
      end if
      if(word ==1&&a[j-1] ==' ')
        a[j-1] = 0 //特殊判断,当仅有一个字母时 且前面都为空格
      end if
    

    2.3.2 代码截图

    2.3.3 请说明和超星视频做法区别,各自优缺点。

    大概思路相同,都是用if来判断处理各类特殊条件。

  • 相关阅读:
    Java技术路线--2循环
    Java技术路线--1基本类型与包装类
    Linux内存管理之UMA模型和NUMA模型
    最长XX子串/数组/子序列
    epoll LT 模式和 ET 模式详解
    OS篇:OS中进程的阻塞与挂起的区别
    约瑟夫环问题
    最大公约数和最小公倍数
    C++之寻找素数(素数筛)
    Linux OOM机制分析
  • 原文地址:https://www.cnblogs.com/jy00/p/14197751.html
Copyright © 2020-2023  润新知