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

    由于“✳”在博客中的效果会使字体倾斜,并且“✳”将显示不出来,因此此篇博客将用中文拼出的“✳”来代替*,请读者明白后阅读。

    0.展示PTA总分

    1.本章学习总结

    1.1 学习内容总结

    指针的概念:
    变量的指针就是变量的地址。变量的值和变量的地址是不同的概念,变量的值是该变量在内存单元中的数据。
    用来存放指针(地址)的变量就称为指针变量。
    知识点:
    1、若把某变量的地址赋值给指针变量p,则称指针变量p指向该变量。

    2、定义指针变量的一般形式为:类型名✳指针变量名;其中“✳” 为说明符,而不是运算符。

    3、通常指针变量可以通过以下几种方法获得地址:通过地址运算"&” 赋值;指针变量的初始化,通过其他指针变量赋值用NULL给指针变量赋空值;以及通过调用标准函数赋值。

    4、“✳”称为指针运算符(单目运算符),也称取内容运算符。当指针变量p指向-个变量x时,可以用 ✳p的形式存取该变量的值。此时,✳p与变量x相互等价。

    5、取地址运算符“&”与指针运算符“✳” 作用在一起时,有相互”抵消”的作用。对于变量x, ✳&x与x相互等价。

    6、比如,若定义了一维数组a和指针变量,且p=a; 则以下四种表示相互等价: a[]、 p[i]、 ✳(a+i)、 ✳(p+i)。

    7、未对指针变量p赋值即p没有指向时,而就对✳p赋值,该值就代替了内存中某单元的内容,有可能出现不可意料的错误。

    8、一个数组的元素在内存中是连续存放的,数组第一个元素的地址称数组的首地址。在C语言中,数组名是该数组的首地址,因此,数组名是指针常量。

    9、当指针变量p指向数组元素时,p加上一个正整数n, 则当前指向为相对p向前移动n个元素的位置; p减去一个正整数n,则当前指向为相对p向后移动n个元素的位置。

    10、C语言的二维数组由若干个一维数组构成。若有定义语句:int a[M][N],i, j;则以下元素的四种表示相互等价:a[i][j]、✳(a[i]+j)、 ✳(✳(a+i)+j)、(✳(a+i))[j]。

    11、字符指针表示字符串:比如char *p="hello";输出的时候这样就可以了:printf("%s",p);这里p指的是"hello"的首字符的地址,用%s可以连接后面的字符一起输出,直到遇到'';

    12、指针做函数参数:返回指针的函数一般都返回:全局数据对象、主调函数中数据对象的地址;比如定义在main函数上面的全局变量,函数中的static型的变量。
    要记住的是:不能在实现函数时返回在函数内部定义的局部数据对象的地址。(因为局部变量数据对象在函数返回时就会消亡,其值不再有效)

    13、二级指针、行指针:这里可以联系二维数组,比如a[n][m],则a就是一个二级指针,指的是a[0]、a[1]、a[2]...的地址,而a[0]、a[1]、a[2]是一级指针,指的是a[0][0]、a[1][0]、a[2][0]的地址。

    1.2 本章学习体会

    • 一开始听指针时,什么都不懂,就把它当作是一个指着某个位置的“针头”,这个位置就是指针所指的地址,就这样形象的把指针给可视化了,慢慢的,做到指针的时候就会想象出一个“针头”,指在某个位置,尤其是字符串的时候,会想象出某个字符下面有一个针头指着,还好我用这种形象化的理解,不然真不知道该怎么运用指针。还有就是课前预习、课后复习那些依旧是不变的真理。

    • 本章代码量约600行。

    2.PTA实验作业

    2.1 题目:7-3 字符串的冒泡排序

    2.1.1伪代码:

    定义n,k;
    定义 字符型指针数组strP[102];
    char Temp[12];//冒泡交换字符串时的中间变量
    
    scanf("%d %d", &n, &k);//输入n和k
    用getchar();吸收换行符
    
    for
    申请动态储存空间给strP[i];
    输入一串字符串给strP[i]所指向的地址
    当i=n-1时end for
    for (i = 0; i < k; i++)//两层for,冒泡排序,外循环到k
    for (j = 0; j < n - i-1; j++)
    
    if(strcmp(strP[j], strP[j + 1]) > 0)//如果strP[j]所指向的字符串大于strP[j+1]所指向的字符串
    交换strP[j]和strP[j+1]的内容(是一个地址)
    循环换行输出strP[i];
    

    2.1.2 代码截图

    2.1.3 总结本题的知识点:

    1、用字符指针数组输入字符串时,要申请动态储存空间。

    2、冒泡排序:两层for循环,内循环比较两者然后交换,外循环把最大的“沉下去”。

    3、交换字符串,要利用3个strcpy交换,而不是像数字那个简单的交换;

    4、比较字符串,要用strcmp比较,不能用‘>’或者‘<’;

    5、用到操作字符串的函数,要定义头文件string.h

    2.1.4 PTA提交列表及说明

    提交列表说明:
    1、段错误:在输入字符串的时候,在for里面没有定义strP[i] = (char✳)malloc(sizeof(char) ✳ 12);于是出现了错误,无法再次正常输入。

    2、段错误:在for里面scanf("%s", strP[i]);对了一个&号:scanf("%s", &strP[i]);编译过了,但是输入不正常。

    3、格式错误:输出的时候缺少 ,补为:printf("%s ", strP[i])。

    2.2 题目名2:7-4 说反话-加强版

    2.2.1伪代码

    char str[N];//定义一个字符串str
    int flag = 1;//判断是否是第一个输出的单词
    int word = 0;//计算空格之后有几个字符;
    int i, len, sublen;//len为str的长度,sublen为某个单词的长度
    
    输入字符串;
    获得字符串的长度:len = strlen(str);
    
    for循环(从i=len-1开始,到i=-1结束循环)
    if(str[i]是空格并且word不为0)
    {
    *(str + i + word + 1) = 0;//将单词后面的一个字符置为''
    
    判断是否为第一个输出的单词,是则输出%s(str + i + 1)//从空格开始,到单词后面的一个字符'';
    不是第一个输出的单词,则输出%s(str+i)//从单词后开始,到单词末(无空格);
    
    无论是否为1第一个输出的单词,都要将word置0;
    
    }
    else 如果str[i]不为空格,则word++;
    end for
    //for结束后,可能还有一个单词(输入的首单词)
    if(word!=0)
    则判断是否为第一个输出的单词,然后根据判断输出%s或者 %s(有空格)
    
    

    2.2.2 代码截图

    2.2.3 总结本题的知识点

    1、用strlen可以获得str的长度,要声名string.h头文件。

    2、倒序输出单词,要"抓"那个单词前的空格,在for循环内,从末尾往前面搜索空格,然后计算输出

    3、✳(str+i)等价于str[i];用%s输出时,要将单词的末尾置为'',即✳(str+i+word+1)=0;

    4、在PTA上gets可以通过,而gets_s不能过,在VS上,gets_s能过,而gets不能过。

    2.2.4 PTA提交列表及说明

    提交列表说明:
    1、部分正确:空格输出控制判断不完善,第一个单词输出前面不能有空格,要考虑3部分,第一部分是空格后面的单词,第二部分是输入的首单词,还有仅输入一个单词后借空格的情况。这些情况分别考虑后就可以了

    2、部分正确:在单词后面结尾置0时指针位置错误:✳(str + i + word ) = 0;应该为:✳(str + i + word +1) = 0;将单词最后一个字符输出

    3、部分正确:一开始for循环是这样的:for (i = len; i >= 0; i--),导致有一个测试点过不了:一个词,末尾有空格,于是将它改为:for (i = len-1; i >= 0; i--)

    2.3 题目名3:7-5 删除字符串中的子串

    2.3.1伪代码

    定义变量:
    char str[N];
    char SubStr[N];
    char TempStr[N];
    int i, j, k;
    char* p = NULL;
    
    输入2串字符串
    计算子串的长度len = strlen(SubStr) - 1;(-1是为了扣除'
    ')
    将子串的最后一个字符
    删除:*(SubStr + len) = 0;
    用strstr查找字串在母串中相同字符串的地址,记作p
    
    for循环
    *p=0;
    strcpy(TempStr, (p + len));//将(p+len)赋予TempStr
    strcat(p, TempStr);//将TempStr连接到p后面
    
    输出母串str;
    

    2.3.2 代码截图

    2.3.3 总结本题的知识点

    1、查找子串在母串中的位置:用strstr()函数查找,返回的值是一个地址;然后对地址进行操作

    2、在母串处连接另一个字符串:用strcat()函数实现连接,注意连接时要时母串在连接处的数据为'';

    3、判断是否要继续查找删除的条件是(p = strstr(str, SubStr)) != NULL;找得到就继续循环,找不到就退出循环;

    4、fgets会吸收换行符,用strstr时换行符会进入判断字符是否相等的条件,所以用strstr之前,要把子串的最后一个字符置为'';

    2.3.4 PTA提交列表及说明:

    提交列表说明:

    1、部分正确:没有将子串的最后一个字符置为'',导致查找出现错误;

    2、部分正确:一开始拼接母串与除了字符的母串部分用的是:strcat(p, p+len);拼接错误,于是引入TempStr,先储存p+len后的内容,在拼接p与TempStr;

    3、部分正确:字串的长度计算错误:一开始len = strlen(SubStr);这是包含了 的长度,后面删除 后这个长度就错误了,于是改为:len = strlen(SubStr)-1;

    3.阅读代码


    虽然官方题解并没有用到C语言的代码,但是其思路是非常巧妙的,我们一起来欣赏一下:

    这里官方题解用到了3个指针来进行排序:
    第一个指针指着0的最右边界;
    中间,第二个指针指着当前考虑的元素;
    第三个指针指着2的最左边界;

    思路大致是:在循环中(移动第二个指针到达第三个指针的过程):如果第二个指针指着的数值为0,则与第一个指针所指的数据交换,第一个指针++;如果第二个指针指着的数值为2,则与第三指针所指的数据交换,第三个指针--;
    最后,0将被排在数组的最左面,2被排在数组的最右边,而1将被剩下排在中间;

    在这里3个指针同时移动、操作,顺利的仅使用常数空间的一趟扫描算法把一个数组给排序了。

    然后还找到了一个有趣的C语言代码:

    他这里用到了一种 先计数 然后赋值的方法,思路大致是:

    1、定义一个储存数据个数的数组count[3] = {0,0,0},下标代表数据:0、1、2,数组元素则是0、1、2的个数;这里初始化为0;
    2、for(历遍数组),用数组count统计数据0、1、2的个数:count[nums[i]]++;
    3、for(数据0、1、2的赋值),从nums[0]开始赋值count[0]的个数为0;紧接着赋值count[1]的个数为1;然后赋值count[2]的个数为2;

    这种解法并没有给数组排列,而是通过计数重新赋值;虽然有点违背题目的意思,但却顺利的完成了题目的要求;思路非常的巧妙,这简短得令人吃惊的代码量也是这段代码突出的特点之一,思路方法可以学习下来。

  • 相关阅读:
    一行code实现ADO.NET查询结果映射至实体对象。
    傻瓜式使用AutoFac
    Asp.Net MVC中捕捉错误路由并设置默认Not Found页面。
    asp.net MVC中实现调取web api
    JavaScript_11_验证
    JavaScript_10_错误
    JavaScript_9_循环
    JavaScript_8_比较,条件语句
    JavaScript_7_运算符
    JavaScript_6_函数
  • 原文地址:https://www.cnblogs.com/zhangpucyll/p/11965660.html
Copyright © 2011-2022 走看看