代码改变世界

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

2020-12-24 16:28  米奈希尔。  阅读(125)  评论(0编辑  收藏  举报

| 这个作业属于哪个班级 | C语言--网络2011/2012 |
| ---- | ---- | ---- |
| 这个作业的地址 | C博客作业05--指针 |
| 这个作业的目标 | 学习指针相关内容。 |
|姓名 | 罗发槺 |

0.展示PTA总分

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

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

1.指针变量的定义
  • 一般形式:类型名 *指针变量名。
    例如:
    这里是定义了三个指针变量,每次定义都要加指针声明符“ * ”。
  • 指针变量被定义后,必须将他和一个特定的变量关联后才可以使用。指针被赋的值应给是地址,此外还可以是0NULL。例如:

2.指针的相关运算
  • 同种类型的指针之间可以相减,但不可以相加,相减之后得到的是两个指针之间的数组元素个数。
  • 指针每一次加1或减1并非指针的值加1或减1,而是它指向的单元加1或减1。
    例如:int q[2];q++;原本q是指向q[0]但经过加1后,q指向q[1];
  • 指针有加*是对指针指的元素进行运算,没有加是对所指向的元素的地址进行运算。
3.指针做函数参数

在C语言中实参和形参之间的数据传递是单向的“值传道”方式。调用函数不能改变实参变量的值,当指计变量作为函数参数时也遵守这一个规则。调用函数不能改变实参指针变量的值,但可以改变实参指针变量所指向的变量的值,这样的机制被称为引用调用( Call b Referenee)。采用引用调用机制需要在函数定义时将指针作为函数
的形参,在函数调用时把变量的地址作为实参。
例如:

1.2 字符指针及字符串相关函数。

  • 如果定义一个字符指针接收字符串常量的值,该指针就指向字符串的首字符.这样字符数组和字符指针都可以用来处理字符串。
    例如:
char sa[]="abc";
char *sp="def";
printf("%s ",sa);
printf("%s ",sp);
printf("%S","gh");
输出:abc def gh
  • strcat:字符串连接函数。
    用法:strcat(s1,s2);这样就可以将s2的字符串连接到s1上了。
    例如:
char s1[20]="asdf",s2[10]="ghjk";
strcat(s1,s2);

经过连接函数后是的字符串就变成asdfghjk;另外,该函数是识别字符串结束符'\0'来连接的如果你经过s1[2]=0;这步操作后再strcat(s1,s2);那么s1的字符串将变成asghjk。所以只要你想,连接函数也可以当复制函数来使用。

  • strcpy:字符串复制函数。
    用法:strcpy(s1,s2);
    例如:
char s1[20],s2[10]="ghjk";
strcpy(s1,s2);

输出ghjk
当然,strcpy也可以像strcat把连接变成复制一样,strcpy也可以把复制变成连接。
例如:

  • strcmp:比较字符串大小函数。
    例如:
int a;
char s1[20]="asdf",s2[10]="asde";
a=strcat(s1,s2);

如果s1<s2,a=-1;s1>s2,a=1;s1=s2,a=0;这个函数是逐个比较字符串的字母大小的,上面的例子就是先比较a然后比较b这样一直到出现不同或全部比完为止。因为fe大所以上面这个例子的a=1

  • strlen:计算字符串字符个数函数。
    用法:strlen(字符数组名)。

下面这些就不做解释了:

1.3 指针做函数返回值

格式如图:


pos也是指针
注意事项:

  • 1.不能返回在函数内部义的在栈区局部数据对象的地址,这是因为所有的栈区局部数据对象在函数返回时就会消亡,其值不再有效。
  • 2.返回指针的函数一般都返回全局数据对象或指向字符常量指针或维区的指针或主调函数中数据对象的地址

1.4 动态内存分配

  • 为什么要动态内存分配:一般情况下,运行中的很多存储要求在写程序时无法确定,因此需要一种机制可以根据运行时的实际存储需求分配适当的存储区,用于存放那些在运行中才能确定数量的数据。C语言为此提供了动态存储管理机制,允许程序动态申请和释放存储空间。

  • 堆区和栈区区别。

    • 堆:是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便,另外,在windows下,最好的方式是用virtualalloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。

    • 栈:存局部变量,定义的参数,比如int,char之类的,以及调用现场存在栈区,在函数结束时,系统会自动收回存储单元。由系统自动分配,速度较快。但程序员是无法控制的。

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

    malloc用法:要赋值的数组=(强转类型)malloc(sizeof(类型)*长度)
    例子:

callloc用法:要赋值的数组=(强转类型)callloc(长度,sizeof(类型))
例子:

以上课时学到的多个字符串做动态内存要如何分配为例。

#include<stdio.h>
#include<stdlib.h>
int main(){
    int i, n = 0;
    char *color[20], str[15];
    scanf("%s", str);
    while(str[0] != '#'){
        color[n] = (char *) malloc( sizeof(char) * ( strlen(str) + 1 ));//为每行字符串分批内存。
        strcpy(color[n], str);//将每行字符串复制进字符串指针。
        printf("n = %d %s\n\n", n, color[n]);
        n++;
        scanf("%s", str);
    }
    for(i = n - 1; i >= 0; i--){
        printf("%s ", color[i]);
        free(color[i]);
    }
    return 0;
} 

1.5 指针数组及其应用

  • 多个字符串用二维数组表示和用指针数组表示区别:
    • 二维字符数组一旦定义,那么每个字符串的最大长度、首地址都不能改变了。

    • 字符指针数组,顾名思义,它是存放字符指针的数组。由于它仅用来存放指针,所以它指向的每个字符串的首地址可以改变,字符串最大长度也可以改变。
      相比而言,字符指针数组更灵活一些。

1.6 二级指针

C语言中指向指针的指针就是所谓的二级指针,一般定义为:类型名 **变量名;
具体看下图

1.7 行指针、列指针.

先定义一个二维数组
int a[10][10];
然后int **p;
此时,p既可以作行指针,又可以作列指针。
样例如图:

2.PTA实验作业(7分)

2.1 题目名1(2分)

定义数组,循环变量,
利用循环输入
利用循环连接
输出
2.1.1 伪代码
2.1.2 代码截图

2.1.3 找一份同学代码


我是先利用循环输入然后在利用循环来连接,我同学是直接一个循环边输入边连接,相对于我的代码效率更高。

2.2 题目名2(2分)

2.2.1 伪代码
定义一个指针变量num来存数组
定义i,j,k;来控制下标和循环次数
给num分配内存
for i=j=k=0,当不满足 j<n&&i<m 退出循环,每次k++
      if a[i] < b[j]
          num[k] = a[i++];
      end if
      else
          num[k] = b[j++];
end for
while (i < m)
      num[k++] = a[i++];
end while
while (j < n)
      num[k++] = b[j++];
end while 
for i = 0; i < m + n; i++
      a[i] = num[i];
end for
2.2.2 代码截图

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

同学的代码:

  • 我的代码是再定义一个数组来存放排序的数组,然后再把排好序的数组赋值给a数组。
  • 同学的代码是用数组a长度的特点,从逆向重构数组,这样做的话:不需要重新定义一个的数组来分别存放,效率更高。

2.3 题目名3(3分)

2.3.1 伪代码
定义i来控制循环和下标
定义flag来控制输出格式
定义len来存放字符串的长度
定义str来存放字符串
用fgets输入字符串
计算并存放字符串str中字符的个数
将回车符用0覆盖;
for len-1 to 0
      if str[i] == ' ' && str[i + 1] == 0
            str[i]=0;
      end if
      else if str[i] == ' '
            if str[i - 1] == ' ' && flag == 0
                  输出调整之后的字符串
            end if
            else 
                  输出调整之后的字符串
            end else
            str[i] = 0;
            flag = 1;
      end else
end for
输出最开头的单词
2.3.2 代码截图

2.3.3 请说明和超星视频做法区别,各自优缺点。
  • 超星的做法是利用循环来遍历计算字符串的长度,然后用空格做判断条件来输出。
    • 优点:可以用指针来灵活表示字串。
    • 缺点:实现方法略为复杂。
  • 我是通过每次将空格转换成结束符来控制输出,每次输出找到的空格地址之后的字符串。
    • 优点:方法简单清晰,代码简洁明了且量少,可以直接对字符串操作而不用每次计算子串的字符数量。