C语言博客作业05--指针

梦想的初衷 提交于 2019-12-06 06:36:13

0.展示PTA总分

1.本章学习总结

1.1 学习内容总结

1.如果事先无法确定需要处理的数据数量,有两种处理方法:一种方法是估计一个上限,并将该上限作为数组长度,但是这样常常会造成空间浪费;另一种方法是利用指针来实现存储空间的动态分配

2.使用指针可以对复杂数据进行处理,能对计算机的内存分配进行控制,在函数调用中使用指针可以返回多个值

3.一般数据是按照“地址”存取的

4.程序执行时将变量翻译为它所在的内存地址来进行操作,这种使用变量的方法叫做“直接访问”,直接访问一般以内存单元的第1个字节的地址作为它的地址

5.在C程序中还有一种使用变量的方法,即通过变量的地址进行操作,用指针访问内存和操纵地址,比如再定义一个变量来专门存放另一个变量的地址,这种方法称为“间接访问”

6.在C语言中把专门用来存放变量地址的变量称为“指针变量”,简称为指针

7.指针是用来存放内存地址的变量,如果一个指针变量的值是另一个变量的地址,就称该指针变量指向那个变量

8.&n表示变量n的内存地址或存储位置,&被称作地址运算符,&是一元运算符,与其他的一元运算符有同样的优先级和从右到左的结合性

9.定义指针的一般形式为:

类型名 * 指针变量名

  • ps:* 指的是指针声明符

10.在许多场合,可以把指针变量简称为指针,但实际上指针和指针变量在含义又上存在一定的差异,一般来说,在C语言中,指针被认为是一个概念,而指针变量本身就是变量,和一般变量不同的是它存放的是地址。大多数情况下,并不特别强调它们的区别,都是指存放内存地址的指针变量

11.指针值可以是特殊的地址0,也可以是一个代表机器地址的正整数

12.指针变量用于存放变量的地址,由于不同类型的变量在内存中占用不同大小的存储单元,所以只知道内存地址,还不能确定该地址上的对象,因此在定义指针变量时,除了指针变量名,还需要说明该指针变量所指向的内存空间上所存放的数据的类型

13.定义多个指针变量时,每一个指针变量前面都必须加上*

14.指针变量的类型不是指指针变量本身的类型,面是指它所指向的变量的数据类型

15.无论何种类型的指针变量,它们都是用来存放地址的,因此指针变量自身所占的内存空间大小和它所指向的变量数据类型无关,尽管不同类型的变量所占的内存空间不同,但不同类型指针变量所占的内存空间大小都是相同的

16.指针变量被定义后,必须将指针变量和一个特定的变量进行关联后才可以使用它,也就是说,指针变量也要先赋值再使用,当然指针变量被赋的值应该是地址

17.对指针变量p赋值:

p=&i;//指针p被看作存放变量i的地址
p=0;//将特殊值0赋值给指针p
p=NULL;//将特殊值0赋值给指针p
p=(int * )1732;//使用强制类型转换(int * )来避免编译错误,表示指针p指向地址为1723的int型变量

18.在对指针变量命名时(除整型指针外),建议用其类型名的首字母作为指针名的首字符

19.在定义指针变量时,要注意:

<1>指针变量名是一个标识符,要按照C标识符的命名规则对指针变量进行命名

<2>指针变量的数据类型是它所指向的变量的类型,一般情况下一且指针变量的类型被确定后,它只能指向同种类型的变量

<3>在定义指针变量时需要使用指针声明符“*”,但指针声明符并不是指针的组成部分。如:定义int *p;说明p是指针变量,而不是 *p

20.在对指针变量命名时(除整型指针外),建议用其类型名的首字母作为指针名的首字符,用p或ptr作为名字,以使程序具有较好的可读性。如将单精度浮点型指针取名为fp,fptr,f_ptr等

21.如果指针的值是某个变量的地址,通过指针就能间接访问那个变量,这些操作由取地址运算符&和间接访问运算符*完成。此外,相同类型的指针还能进行赋值,比较和算术运算


(1)取地址运算和间接访问运算

<1>单目运算符&用于给出变量的地址
<2>“*”除了被用于定义指针变量以外,还被用于访问指针所指向的变量,它也被称为间接访问运算符。例如:当p指向a时,*p和a访问同一个存储单元,*p的值就是a的值
<3>表达式*p=*p+1、++*p和(*p)++,都是将指针p所指向变量的值加1,而表达式*p++等价于*(p++),先取*p的值作为表达式的值,再将指针p的值加1,运算后,p不再指向变量a
<4>带有间接地址访问符*的变量的操作在不同的情况下会有完全不同的含义

(2)赋值运算

<1>

22.两个相同类型的指针相减,表示它们之间相隔的数组元素数目。要特别注意的是,在C请言中,指针的算术运算只包括两个相同类型的指针相减以及指针加上或减去一个整数,其他的操作如指针相加、相乘和相除,或指针加上和减去一个浮点数都是非法的。

23.两个相同类型指针还可以使用关系运算符比较大小。

1.2 本章学习体会

1.2.1 学习体会

  • 这一段时间的学习比较吃力,关于指针的一些概念理解得不是很明白,做题时也遇到了一些麻烦,在VS上写代码时一直会出错又出错,然后就一点一点地去改,有时候改的原因是什么自己也不清楚(O_O)?
  • 指针的基本运算,符号不同不知道到底怎么分辨,到底有什么区别,有什么特殊含义,比较混乱,没有弄懂
  • 在C语言中实参和形参之间的数据传递是单向的“值传递”方式,当指针变量作为函数参数时,就更搞不明白参数传递了,格式总是写错,在函数调用中不清楚怎么用指针
  • 不明白为什么指针的运算中相加,相乘等运算是非法的
  • 指针的代码读起来比较困难,不太好理解,在刷PTA的时候,也不怎么会用指针来做,有时候就是提一两笔,比较模糊,好多其实都没有用指针,有点尴尬哈 ̄□ ̄||
  • 不过我还是有点问题,就是VS,Dev-C++和PTA有时候这个对,那个错的,让人很纠结啊(ー`´ー)

1.2.2 代码累计

我的代码量(不包括重复)

代码量(行)
4 241
5 506
6 771
7 842
8 793
9 724
10 1980
11 983
12 879
13 545
14 479
累计 9726

2.PTA实验作业

2.1 题目名1

合并两个有序数组(2) (15 分)
要求实现一个函数merge,将元素个数为m的升序数组a和长度为n的升序数组b合并到数组a,合并后的数组仍然按升序排列。假设数组a的长度足够大。

裁判测试程序样例:

#include <stdio.h>
#include <stdlib.h>

void printArray(int* arr, int arr_size);  /* 打印数组,细节不表 */
void merge(int* a, int m, int* b, int n); /* 合并a和b到a */

int main(int argc, char const *argv[])
{
    int m, n, i;
    int *a, *b;

    scanf("%d %d", &m, &n);
    a = (int*)malloc((m + n) * sizeof(int));
    for (i = 0; i < m; i++) {
        scanf("%d", &a[i]);
    }

    b = (int*)malloc(n * sizeof(int));
    for (i = 0; i < n; i++) {
        scanf("%d", &b[i]);
    }
    merge(a, m, b, n);
    printArray(a, m + n);

    free(a); free(b);
    return 0;
}

printArray函数

void printArray(int* arr, int arr_size)
{
    int i;
    for (i = 0; i < arr_size; i++)
    {
        printf("%d ", arr[i]);
    }
}

2.1.1 伪代码

merge函数
开辟c数组
i表示a数组下标,j表示b数组下标,k表示c数组下标
for i=j=k=0 to i<m&&j<n
{
    if(a[i]<b[j])//a数组中的数和b数组中的数比较,较小的放入c数组中
       a[i]放入c数组,i++,k++
    else
       b[j]放入c数组,j++,k++
}
while(i<m)  a剩下数据元素放入c
while(j<n)  b剩下数据元素放入c
c数组复制a数组//题目要求合并后的升序数组仍然存放在a中
释放c数组

2.1.2 代码截图


2.1.3 总结本题的知识点

1. 可以多定义一个新的数组c来先储存最后得到的数列,然后再将c数组复制到a数组中
2. a和b是按升序排列的数组,所以可以让a数组中的数和b数组中的数从第一个数开始依次比较,然后将较小的放入c数组中
3. 使用c数组结束后需要释放数组

2.1.4 PTA提交列表及说明

提交列表说明:

2.2 题目名2

说反话-加强版 (20 分)
给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。

2.2.1 伪代码

#define N 500010//在一行内给出总长度不超过500000的字符串
定义函数ReverseStr(char* beginPtr);
int main()
{
    char str[N];

    fgets(str, N - 1, stdin);

    ReverseStr(str);

    return 0;

}

void ReverseStr(char* beginPtr)
{
    char* endPtr;
    char* p;
    int len;
    int flag;

    endPtr = beginPtr;
    flag = 1;

    while (*endPtr && *endPtr != '\n')
    {
        endPtr++;
    }

    p = --endPtr;
    len = 0;

    while (p != beginPtr)
    {
        if (*p != ' ')
        {
            len++;
            if (*(p - 1) == ' ')
            {
                if (flag)
                {
                    printf("%.*s", len, p);
                    flag = 0;
                }
                else
                {
                    printf(" %.*s", len, p);
                }
                len = 0;
            }
        }
        p--;
    }

    if (*p != ' ')
    {
        if (flag)
        {
            printf("%.*s", len + 1, p);
            flag = 0;
        }
        else
        {
            printf(" %.*s", len + 1, p);
        }
    }

}

2.2.2 代码截图




2.2.3 总结本题的知识点

2.2.4 PTA提交列表及说明

提交列表说明:

2.3 题目名3

删除字符串中的子串 (20 分)
输入2个字符串S1和S2,要求删除字符串S1中出现的所有子串S2,即结果字符串中不能包含S2。

2.3.1 伪代码

2.3.2 代码截图

2.3.3 总结本题的知识点

2.3.4 PTA提交列表及说明

提交列表说明:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!