zoukankan      html  css  js  c++  java
  • C博客作业05—指针

    0.展示PTA总分(0----2)

    展示关于“指针题目集”分数截图。

    1.本章学习总结(2分)

    1.1 学习内容总结

    (1) 指针做循环变量做法

    #include<stdio.h>
     
    void main()
    {
        int arr[]={6,4,3,5,8,1};
        int len = sizeof(arr);
        for(int i=0;i<len;i++)
        {
            printf("%d
    ",arr[i]);//常规遍历方式
        }
        for(int i=0;i<len;i++)    
        {
             printf("%d
    ",*(arr+i));//使用arr指针遍历方式
        }
        int *p_arr=arr;
        for(int i=0;i<len;i++)
        {
             printf("%d
    ",*(p_arr+i));//额外使用新指针来遍历数组
             printf("%d
    ",*p_arr++);//额外使用新指针来遍历数组
        }
    }
    

    (2) 字符指针如何表示字符串

    • C语言中没有特定的字符串类型,我们通常是将字符串放在一个字符数组中。字符数组归根结底还是一个数组,当然关于指针和数组的规则同样也适用于字符数组。举一个例子:
    #include <stdio.h>
    #include <string.h>
    int main(){
        char str[] = "asdfghjkl";
        char *pstr = str;
        int len = strlen(str), i;
        /*使用*(pstr+i)形式*/
        for(i=0; i<len; i++){
            printf("%c", *(pstr+i));
        }
        printf("
    ");
    
        /*使用pstr[i]形式*/
        for(i=0; i<len; i++){
            printf("%c", pstr[i]);
        }
        printf("
    ");
    
        /*使用*(str+i)形式*/
        for(i=0; i<len; i++){
            printf("%c", *(str+i));
        }
        printf("
    ");
        return 0;
    }
    

    上面的三种输出形式输出的结果都是一样:asdfghjkl
    除了字符数组,C语言还支持另外一种表示字符串的方法,就是直接使用一个指针指向字符串,例如:

    char *str = "asdfghjkl";
    

    或者:

    char *str;
    str = "asdfghjkl";
    

    字符串中的所有字符在内存中是连续排列的,str 指向的是字符串的第 0 个字符;我们通常将第 0 个字符的地址称为字符串的首地址。字符串中每个字符的类型都是char,所以 str 的类型也必须是char *。

    (3) 动态内存分配

    首先,我们应该知道。所有的程序都必须留出足够的内存空间来存储所使用的数据,所以我们常常会预先给程序开辟好内存空间,然后进行操作。例如,我们经常会利用数组来储存我们需要的数据。但是利用数组的时候需要提前设置数组长度。在今后的学习中我们经常会不知道数据大小是多少,如果直接设置一个较大的量大的话会导致空间的浪费,并且,如果数据超过了数组数据类型最大长度的话,也会造成错误。对于传统数组,会遇到这种问题:
    
    int arr[5] ;
    
    • malloc()函数;
      对这个数组我们在定义的时候必须给提前开辟好空间。而且在程序运行的过程中,这个开辟的内存空间是一直存在的。除非等到这个函数运行完成,才会将空间释放。
      另一个问题就是这个数组在程序中无法被改动。这些问题给我们造成了一些使用上的不方便,所以,C中提供了malloc()函数。 关于malloc()函数。这个函数它接受一个參数:就是所需的内存的字节数。然后malloc()找到可用内存中那一个大小适合的块。在这个过程中,malloc()能够来返回那块内存第一个字节的地址。所以。也就意味了我们能够使用指针来操作。malloc()能够用来返回数组指针、结构指针等等。所以我们须要把返回值的类型指派为适当的类型。当malloc()找不到所需的空间时。它将返回空指针。例如:
    int *p;
    p=(int*)malloc(3*sizeof(int));
    

    在这个程序中,首先开辟了3个int类型的空间,然后把p指向这个空间的位置。在这里的指针是指向第一个int值。并非我们所有开辟的3个int的空间。这就和数组一样,指向数组的指针式指向数组首元素的地址,并非整个数组的元素。所以,在这里我们的操作也和数组是一样的, p[0]就是第一个元素。p[2]就是最后一个元素。 至此。我们就能够掌握到一种声明动态数组的方法。(不要忘记要将该动态内存的首地址进行强制类型转化换成int型并存放在指针p中)

    int arr[n];
    p=(int *)malloc(n*sizeof(int));
    //我们在这里使用的时候要元素个数乘类型字节长度。这样就达到了动态开辟内存空间。
    
    • free()函数;
      当我们使用malloc()开辟完内存空间以后,我们所要考虑的就是释放内存空间,在这里,C给我们提供了free()函数。free()的參数就是malloc()函数所返回的地址,释放先前malloc()函数所开辟的空间。 如果申请了动态内存而没有及时释放的话,会造成内存的溢出;

    • calloc()函数;
      与 malloc() 相比有两个优点:
        (1)它把内存分配为给定大小的数组;
        (2)它初始化了所分配的内存,所有位都是 0。

    int *pNumber = (int*)calloc(75, sizeof(int));    
    // 分配了包含75个int元素的数组
    

    如果不能分配所请求的内存,返回值就是 NULL。

    • relloc()函数;
      realloc() 函数可以重用或扩展以前用 malloc()或 calloc()(或者realloc())分配的内存。
      realloc()的两个参数:
      1)、一个是包含地址的指针,该地址以前由malloc()、colloc()或realloc()返回。
      2)、要分配的新内存的字节数。
        realloc()函数分配第二个参数指定的内存量,把第一个指针参数引用的、以前分配的内存内容传递到新分配的内存中,传递的内容量是新旧内存中区域较小的那一个。
       
       realloc()函数返回一个指向新内存的void指针,如果分配失败,返回NULL。如果第一个参数是NULL,就分配第二个参数指定的新内存,类似malloc()。
       
       realloc()保存了原内存区域的内容,且保存的量是新旧内存区域中较小的那个。如果新内存区域大于旧内存区域,新增的内存就不会初始化,而是包含垃圾值。

    (4) 指针数组及其应用

    数组(Array)是一系列具有相同类型的数据的集合,每一份数据叫做一个数组元素(Element)。数组中的所有元素在内存中是连续排列的,整个数组占用的是一块内存。定义数组时,一定要给出数组名,数组名可以认为是一个指针,它指向数组的第 0 个元素。在C语言中,我们将第 0 个元素的地址称为数组的首地址。虽然可以认为是一个指针,但你在定义时在数组变量名前面加 * ,这就不是一个常规的数组了,而是指针数组,里面的所有元素都是指针。
    
    #include<stdio.h>
    void main()
        {
        int arr[] = {1,2,3,4,5,6};
        //这里的变量名arr里面存放的有该数组的第一个数据的地址也就是arr[0]的地址值
        //所以可以认为arr就是该数组的指针
        int *p=arr;
        int *arr[]={p};
    

    (5)二级指针、行指针

    • (1)二级指针
      指针可以指向一份普通类型的数据,例如 int、double、char 等,也可以指向一份指针类型的数据,例如 int *、double *、char * 等。如果一个指针指向的是另外一个指针,我们就称它为二级指针,或者指向指针的指针。
    int a =100;
    int *p1 = &a;
    int **p2 = &p1;
    
    指针变量也是一种变量,也会占用存储空间,也可以使用&获取它的地址。C语言不限制指针的级数,每增加一级指针,在定义指针变量时就得增加一个星号*。p1 是一级指针,指向普通类型的数据,定义时有一个*;p2 是二级指针,指向一级指针 p1,定义时有两个*。你想是几级的指针,p前面就加几个*。
    
    * 行指针;
    行指针,顾名思义就是指向一行的指针。在二维指针中,行指针用的最多。我们通常把二维指针看成一个行列式,但是它在内存中的排序却是和一维指针一样的。比如组a[2][3]={{1,2,3}{4,5,6}},a是整个数组的首地址,同时也指向第一行元素,即a是一个行指针,它每加1,所指地址移动二维数组的一行,a+1指向第二行元素。对a取*,即*a指向第一行第一个数,*(a+1)指向第二行第一个数,可见,对行指针取值就成了列指针,此时它还是个指针。它每加1,所指地址移动一个元素,*(a+1)+1指向第二行第二个元素,也可以写成a[1]+1。**a(也可写成a[0][0])就是这个二维数组第一行的第一个元素,**(a+1)(也可写成a[1][0])就是第二行的第一个元素,*(*(a+1)+1)(也可写成a[1][1])是第二行的第二个元素。可见,对行指针取2次*就成了某个元素的值了,而不再是地址。
    

    (6)函数返回值为指针

    指针可以作为函数的参数传给函数,那么也一定可以作为函数的返回值,返回给调用函数。比如,写一个返回两者之中较长字符串的函数的示例代码:
    
    #include<stdio.h>
    #include<string.h>
     
    char *compare(char *str1,char *str2){
        if(strlen(str1)>strlen(str2)){
            return str1;
        }else if(strlen(str1)<strlen(str2)){
            return str2;
        }else{
            char *r = "一样长";
            return r;
        }
    }
    void main(){
     
        char *str1 = "123";
        char *str2 = "1234";
        char *r=compare(str1,str2);
        printf("%s
    ",r);
    }
    打印结果:1234
    

    用指针作为函数返回值时需要注意的一点是,函数运行结束后会销毁在它内部定义的所有局部数据,包括局部变量、局部数组和形式参数等,函数返回的指针请尽量不要指向这些临时数据,谁都不能保证这些临时的数据一直有效,它们在后续使用过程中可能会引发运行时错误。

    1.2 本章学习体会

    之前听说,C语言有两大利器:指针和强制转化。其中指针更是C语言的灵魂。过了指针这一关才算是真正学习了c语言。刚开始接触的时候感觉一脸懵,完全不知道指针的作用是什么。书上的文字描述也比较生涩难懂,一度不知道该如何学习C。直到上课的时候,老师讲指针就像是一个行走的箭头,它会走向你想要的对象的地址,在我脑海里形成了完整的运行图。后来对于二级指针的理解也就更加深刻了。这一部分比较难,学起来也比较吃力,尤其是在自己编写代码的时候,所以可能还是自己没有用足够多的时间在这上面才会这样吧。
    
    时间 代码量
    十三周 1103
    十四周 1002

    2.PTA实验作业(7分)

    2.1(指针做函数返回值) 查找指定字符

    2.1.1 伪代码

    
    	函数定义
    	定义字符变量op;
    	定义数组str[M];
    	定义循环变量i;
    	定义整型变量len计算数组长度;
    	
    	输入字符串存入字符数组中以及输入要查找的字符;
    	自定义一个Search函数搜索字符所在的位置;
    	if (Search(str, op) != NULL)
    	{
    		输出下标index;
    	}
    	else
    	{
    		输出"Not Found";
    	}
    char* Search(char* str, char op)
    {
    	char* p;//定义一个新指针存位置,并且这个指针应该为空;
    	p = NULL;
    
    	for str to *str==''
    	{ 
    		if (*str == op) p = str;
    	}
    	return p;返回指针;
    }
    

    2.1.2 代码截图

    2.1.3 总结本题的知识点

    (1)如何利用指针做函数的返回值来解决问题;

    char* p;//定义一个指针,用来储存找到字符的地址,作为返回;
    p = NULL;
    for (str; *str != ''; str++)
    {
    	if (*str == op)
    	{
    		p = str;
    	}
    }
    return p;
    

    (2)要知道计算数组长度要用strlen()函数,但是这个函数后面的括号中不能为空指针(NULL)。

    2.1.4 PTA提交列表及说明

    1.多种错误:开始的时候并没有好好理解题目,所以多种错误;
    2.部分正确:之前的做法是在函数内部定义了一个整型变量,返回值的时候返回这个整数值,但是呢,这是一个指针型的函数,所以错误了;
    3.部分正确:计算数组长度要用strlen()函数,但是这个函数后面的括号中不能为空指针(NULL);我开始的做法是在主函数里面定义一个index;用strlen()来计算它的下表,这样的作法会令大部分测试点过去,但是第一个测试点过不去;
    4.全部正确:终于等到你。。。

    2.2 删除字符串中的子串

    2.2.1

    定义指针*p记录子串查找结果;
    定义字符数组mother[81],son[81]分别输入母串和子串;
    定义整型变量len计算子串长度;
    
    输入母串;
    输入子串;
    while (p = strstr(mother, son)) != NULL  如果strstr函数返回值不为NULL,证明有查找到子串,这里用了strstr函数;
       *p = '';   将找到子串的位置赋一个结束符‘’
        len=strlen(son);计算字串的长度;
       strcat(mother, p + len);   跳过字符串长度个数,将字符串的后半部分复制到结束符之前的部分
    end while
    输出母串;
    

    2.2.2 代码截图

    2.2.3 总结本题的知识点

    • strstr()函数查找子串
      包含文件:string.h
      函数名 : strstr
      函数原型:
    extern char  * strstr(char  * str1, const char  * str2);
    

    语法:

    * strstr(str1, str2)
    

    str1: 被查找目标 string expression to search.
    str2 : 要查找对象 The string expression to find.
    返回值:若str2是str1的子串,则返回str2在str1的首次出现的地址;如果str2不是str1的子串,则返回NULL。
    例子:

    char  * strstr(const char * s1, const char * s2)
    {
    	int len2;
    	if (!(len2 = strlen(s2)))//此种情况下s2不能指向空,否则strlen无法测出长度,这条语句错误
    		return(char*)s1;
    	for (; *s1; ++s1)
    	{
    		if (*s1 == *s2  && strncmp(s1, s2, len2) == 0)
    			return(char*)s1;
    	}
    	return NULL;
    }
    

    2.2.4 PTA提交列表及说明

    1.多种错误:没有用strstr()函数的时候觉得很麻烦,尤其是子串找完一次之后再继续找。所以多种错误;
    2.编译错误:!与=之间多打了一个空格;
    3.全部正确:终于等到你。。。

    2.3 题目名3 用指针将数组中的元素逆序存放

    2.3.1 伪代码

    void inv(int* x, int n)
    {
    	函数定义
    		定义一个整型指针;
    		定义一个整型变量i;
    		定义整型变量t;
    
    	for  p=x  to i<n/2
    		//进行首尾交换
    	
    		t = *(p + i);
    		*(p + i) = *(p + n - 1 - i);
    		*(p + n - i - 1) = t;	
    }
    

    2.3.2 代码截图

    2.3.3 总结本题的知识点

    指针的简单运用,利用指针的遍历解决首尾交换的问题,理解指针的用法。
    

    2.3.4 PTA提交列表及说明

    1.答案错误:没有理解交换之间的关系,导致出现了错误;
    2.全部正确:。。。

    3.阅读代码(-2--1分)


    这是一个解决合并两个有序数组问题的一个方法。和老师讲的不一样的是,它运用了倒序进行比较的方法,大大减少了代码量。但是呢,这种方法还是无法通过较大数据量的测试点。所以,还有下面的方法:

    将指针p1 置为 nums1的开头, p2为 nums2的开头,在每一步将最小值放入输出数组中。便于理解。

  • 相关阅读:
    java 面试每日一题2
    java 面试每日一题
    java GUI画满天星
    java JPEGImageEncoder;图像处理
    spring mvc+myBatis配置详解
    myeclipse 常用快捷键总结
    Java 如何快速序列化
    java UUID
    vue +echarts树状图
    在线预览(pptx、ppt、pps、docx、doc、xlsx、xls)
  • 原文地址:https://www.cnblogs.com/shenchao123/p/11965133.html
Copyright © 2011-2022 走看看