• C语言博客作业05——指针


    0.展示PTA总分

    1.本章学习总结

    1.1 学习内容总结

    •指针做循环变量做法

    1.使指针移动,指向下一个地址单元,改变了指针原本指向的位置。
    2.下标法,寻找离指针指向位置i个单位的位置,不会改变了指针原本指向的位置。

    •字符指针如何表示字符串

    用字符指针指向一个字符串的首地址。

    •动态内存分配

    void *malloc(size_t size);

    函数 malloc()分配连续的内存区域,其大小不小于 size,需要强制类型转换。malloc()获得内存区域时,内存中的内容没有初值。
    2. ```
    void*calloc(size_t n,size_t size);
    

    calloc()函数功能是动态分配n个大小为size的内存空间,需要强制类型转换。calloc()函数会将所申请的内存空间中的每个字节都初始化为0。
    3. ```
    void * realloc(void * ptr,size_t size);

    realloc() 函数可以做到对动态开辟内存大小的调整(既可以往大调整, 也可以往小调整)。ptr为需要调整的内存地址,size为调整后需要的大小(字节数)。
    4. ```
    void free(void* ptr);
    

    申请的动态内存不再使用时,要及时释放。free()不能重复释放一块内存。在free()函数之后需要将ptr再置空 ,即ptr = NULL;
    如果不将ptr置空的话,后面程序如果再通过ptr会访问到已经释放过无效的或者已经被回收再利用的内存, 为保证程序的健壮性, 一般我们都要写ptr = NULL; 。

    •指针数组及其应用

    指针数组就是存放指针的数组,其本质为数组且每个数组元素是指针。
    应用:6-7 输出月份英文名

    char* getmonth(int n)
    {
    	char* p[12] = { "January","February","March","April","May","June","July","August","September","October","November","December" };
    	if (n > 12 || n < 1) return NULL;
    	return p[n - 1];
    }
    

    •二级指针、行指针

    二级指针 :int * * ptr:数据类型是int * * ,即指向指针的指针,是个二级地址。
    行指针:指向某一行,不指向具体的元素。

    •函数返回值为指针

    指针函数的定义,顾名思义,指针函数即返回指针的函数。

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

    1.2 本章学习体会

    学会了指针,能够对地址直接进行操作。对于二级指针、行指针、指针数组、指针函数不太理解,也不太会用。

    代码量:480行

    2.PTA实验作业

    2.1 6-4 求出数组中最大数和次最大数

    2.1.1 伪代码

    int fun(int* a, int n)
    {
    	int t;//交换中间值
    	int* p;//循环变量
    	p = a+1;
    	for (p; p < a + n; p++)
    	{
    		寻找最大值
    	}
    	for (p = a + 2; p < a + n; p++)
    	{
    		寻找次大值
    	}
    	return 0;
    }
    

    2.1.2 代码截图

    int fun(int* a, int n)
    {
    	int t;
    	int* p;
    	p = a+1;
    	for (p; p < a + n; p++)
    	{
    		if (*p > * a)
    		{
    			t = *p;
    			*p = *a;
    			*a = t;
    		}
    	}
    	for (p = a + 2; p < a + n; p++)
    	{
    		if (*p > * (a + 1))
    		{
    			t = *p;
    			*p = *(a + 1);
    			*(a + 1) = t;
    		}
    	}
    	return 0;
    }
    

    2.1.3 总结本题的知识点

    1. 原本的指针不能改变,所以定义一个新指针来做循环变量。
    2. *的优先级比+来得高,所以a+1需要加括号提高优先级。

    2.1.4 PTA提交列表及说明

    答案错误:没有使用新指针来做循环变量。
    答案错误:没有考虑优先级。

    2.2 6-9 合并两个有序数组(2)

    2.2.1 伪代码

    void merge(int* a, int m, int* b, int n)/* 合并a和b到a */
    {
    	int i;
    	int j=0;
    	int k=0;
    	int t;
    	static int h[100001];
    	for (i = 0; i < m; i++)
    	{
    		h[a[i]]++;//将a中出现过的数值用h储存起来
    	}
    	for (i = 0; i < n; i++)
    	{
    		h[b[i]]++;//将b中出现过的数值用h储存起来
    	}
    	for (i = 0; i < 100001; i++)
    	{
    		if (j > m + n - 1) break;
    		if (h[i] > 0)
    		{
    			for (; h[i] > 0;)
    			{
    				利用h重构指针所指内容
    			}
    		}
    	}
    }
    

    2.2.2 代码截图

    void merge(int* a, int m, int* b, int n)/* 合并a和b到a */
    {
    	int i;
    	int j=0;
    	int k=0;
    	int t;
    	static int h[100001];
    	for (i = 0; i < m; i++)
    	{
    		h[a[i]]++;
    	}
    	for (i = 0; i < n; i++)
    	{
    		h[b[i]]++;
    	}
    	for (i = 0; i < 100001; i++)
    	{
    		if (j > m + n - 1) break;
    		if (h[i] > 0)
    		{
    			for (; h[i] > 0;)
    			{
    				a[j] = i;
    				j++;
    				h[i]--;
    			}
    		}
    	}
    }
    

    2.2.3 总结本题的知识点

    题目并不难,但数据量较大,因此需要较为简洁高效的代码来降低时间和空间复杂度。因此使用了h数组来存放数值。

    2.2.4 PTA提交列表及说明

    部分正确:运行超时,因为是先将b接到a后面,再用冒泡排序法进行排序,时间复杂度太高。

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

    2.3.1 伪代码

    #include  <stdio.h>
    #include  <string.h>
    #include  <stdlib.h>
    #include  <ctype.h>
    
    int main()
    {
    	char s1[100];
    	char s2[100];
    	char* p;
    	int l;
    	输入s1,s2;
    	s2长度;
    	s2[l - 1] = 0;
    	l--;
    	while (1)
    	{
    		寻找s2在s1的首地址;
    		*p = 0;
    		strcat(s1, p + l);
    	}
    	printf("%s", s1);
    }
    

    2.3.2 代码截图

    #include  <stdio.h>
    #include  <string.h>
    #include  <stdlib.h>
    #include  <ctype.h>
    
    int main()
    {
    	char s1[100];
    	char s2[100];
    	char* p;
    	int l;
    	fgets(s1, 100, stdin);
    	fgets(s2, 100, stdin);
    	l = strlen(s2);
    	s2[l - 1] = 0;
    	l--;
    	while (1)
    	{
    		p = strstr(s1, s2);
    		if (p == NULL) break;
    		*p = 0;
    		strcat(s1, p + l);
    	}
    	printf("%s", s1);
    }
    

    2.2.3 总结本题的知识点

    1. 将s2最后的' '改为''。
    2. 使用strstr寻找s2在s1中的首地址
    3. NULL的使用。

    2.3.4 PTA提交列表及说明

    部分正确:使用fgets输入s2,最后的字符是' ',且s2的长度不正确。

    3.阅读代码

    7-4 说反话-加强版

    #include <stdio.h>
    #include <string.h>
    int main()
    {
    	char c[500000];
    	char a;
    	int i=0,j, count = 0,flag=0;
    	while ((a = getchar()) != '
    ')
    	{
    		if (a != ' ')
    		{
    			flag = 1;//遇到单词
    			c[i++] = a;
    			count = 0;//重置空格数量
    		}
    		else if (count > 0) continue;//已有一个空格
    		else if(flag)//1==空格前有单词
    		{
    			c[i++] = a;
    			count++;//标记一个空格
    		}
    	}
    	count = 0;
    	i--;
    	for (i; i >= 0; i--)
    	{
    		if (c[i] != ' ')
    		{
    			count++;//统计单词的字母数量
    		}
    		else if (c[i] == ' ' && count > 0)//遇到空格,结束统计,开始输出
    		{
    			for (j = i + 1; j <= i + count; j++)
    			{
    				printf("%c", c[j]);
    			}
    			printf(" ");
    			count=0;
    		}
    		
    	}
    	for (j = i + 1; j <= i + count; j++) //最后一个单词
    	{
    		printf("%c", c[j]);
    	}
    	return 0;
    }
    

    这道题我一开始是想着全部输入再进行查找,但是失败了。而这份代码是边输入边做处理,这跟以往我的方法截然不同。这样子就将输入和遍历两次循环变为一次,大大地节约了时间。
    而且它对于细节的处理也十分到位,例如flag的使用,最后一个单词的特殊处理。

  • 相关阅读:
    关于分布式的一些理解和认识
    Git使用详细教程
    Kettle 7启动 Spoon.bat 时报错“A Java Exception has occurred.”的解决方法
    postgresql 9源码安装
    intel笔记本cpu型号后缀详解(M,U,QM,MQ,HQ,XM)
    LAMP部署流水
    四种mysql存储引擎
    MySQL日志
    MySQL存储引擎总结
    MySQL存储引擎中的MyISAM和InnoDB
  • 原文地址:https://www.cnblogs.com/chenlr/p/11965590.html
Copyright © 2020-2023  润新知