这个作业属于哪个班级 | C语言--网络2011/2012 |
---|---|
这个作业的地址 | C博客作业05--指针 |
这个作业的目标 | 学习指针相关内容 |
姓名 | 吴俊豪 |
0. 展示PTA总分
1. 本章学习总结
1.1 指针定义、指针相关运算、指针做函数参数
int fun(int *a);
int *p;//指针定义
int n;
int num[50];
p = num;
num[0]=1;
*(p)++;//指针所指内容自增
p++;//指针移动到下一位
n=fun(p);//向函数传入指针的地址
常用的string指针库函数
函数名 | 函数格式 | 作用 | 备注 |
---|---|---|---|
strcpy | strcpy(a,b) | 把b字符串内容赋给a字符串 | 可以使用strncpy能自定义赋值的位数 |
strcmp | strcmp(a,b) | 将a串与b串比较 | 1.a大值为1,b大值为-1,相等值为0. 2.可以使用strncmp自定义比较位数 |
strcat | strcat(a,b) | 把b串从头接到a串末尾 | 可以使用strncat自定义追加位数 |
strstr | strstr(a,b) | 在a串中找到b串首次出现的地址 | 不会包含结束符 |
更多string库函数请移步C 标准库 - <string.h>
1.2 字符指针
- 定义字符指针:char *p;
- 字符指针的内容为字符串,字符数组是一种特殊的字符指针.
- 使用printf("%s",p);来输出字符指针的内容.
- 使用指针指向字符串,例:p=(str+i);
1.3 指针做函数返回值
- 指针在函数内无返回值时应return NULL;
- 指针在不同定义类型的函数内的返回值应切合题意返回,诸如int,double,int *,char *等等
1.4 动态内存分配
-
堆区与栈区
(1)栈区:存放函数的参数值、局部变量等,由编译器自动分配和释放,效率很高,但是分配的内存量有限.
(2)堆区:就是通过new、malloc、realloc分配的内存块,编译器不会负责它们的释放工作,需要用程序区释放。分配方式类似于数据结构中的链表。“内存泄漏”通常说的就是堆区.
-
使用函数:
函数名 | 函数格式 | 作用 | 备注 |
---|---|---|---|
calloc | calloc(n,s) | 分配n个大小为s的堆区 | 返回值类型为void,通常需要进行强转 |
malloc | malloc(s) | 分配一个内存大小为s的堆区 | 返回值类型为void,通常需要进行强转 |
注:申请堆区空间后要记得在使用完之后释放.
- 举例多个字符串做动态内存要如何分配
#include<stdio.h>
#include<string.h>//函数malloc的库;
int main()
{
char* a;
char* b;
a = (char*)malloc(m*sizeof(char));//给a申请m个char单位的空间;
b = (char*)malloc(n*sizeof(char));//给b申请n个char单位的空间;
Function(a,b);//使用a,b字符串;
free(a);
free(b);//使用完手动释放内存;
return 0;
}
1.5 指针数组及其应用
二维字符数组:一旦定义,那么每个字符串的最大长度、首地址都不能改变了.
字符指针数组:由于它仅用来存放指针,所以它指向的每个字符串的首地址可以改变,字符串最大长度也可以改变,相较二维字符数组更加灵活.
1.6 二级指针
二级指针就是指向指针的指针.
1.7 行指针、列指针
(1)行指针:通常写作p+i,取值时为(p+i);
(2)列指针:通常写作p[0]+i,取值时为(p[0]+i);
2.PTA实验作业
2.1 藏尾诗
2.1.1 伪代码
ch[20][20]//用于存放诗句
d[20]//用于存放尾巴
i<-0
j<-0
while i<4
do scanf ch[i]
d[j] <- *(ch[i] + strlen(ch[i]) - 2)
d[j+1] <- *(ch[i] + strlen(ch[i]) - 1)//一个汉字占两个字节
j+=2
i++
end while
d[j]<-0//添加结束符
printf d
2.1.2 代码截图
2.1.3 代码比较
同学的代码:
#include <stdio.h>
#include <stdlib.h>
#include "math.h"
#include "string.h"
int main()
{
char *p[4],str[20];
int i;
for(i=0;i<=3;i++){
fgets(str,19,stdin);
p[i]=(char *)malloc(sizeof(str)+1);
strcpy(p[i],str);
}
int n;
for(i=0;i<=3;i++){
n=strlen(p[i])-1;
printf("%s",p[i]+n-2);
}
free(p);
return 0;
}
两份代码最大的区别在于同学使用了动态内存申请,我则选用二维字符数组,相较之下同学的代码可以适应更加极端的情况(诗句数量特别多时).
2.2 合并2个有序数组
裁判测试程序:
#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;
}
2.2.1 伪代码
void merge(int* a, int m, int* b, int n)
static hash[100001]
i,j
for i=0 to m
hash[a[i]]++
end for
for i=0 to n
hash[a[i]]++
end for
for i=0 to 100001
for j=0 to hash[i]
*a = i;
a++
end for
end for
2.2.2 代码截图
2.2.3 代码比较
同学代码:
void merge(int* a, int m, int* b, int n, int* c)
{
int i=0,j=0,k=0;
while(i<m&&j<n)
{
if(*a>=*b)
{
c[k]=*b;
b++;j++;k++;
}
else
{
c[k]=*a;
a++;i++;k++;
}
}
if(i<m)
{
while(k<=m+n-1)
{
c[k]=*a;
a++;
k++;
}
}
if(j<n)
{
while(k<=n+m-1)
{
c[k]=*b;
b++;
k++;
}
}
for(i=0;i<m+n;i++)
{
a[i]=c[i];
}
}
两份代码几乎就是两个不同的思路,同学是先将a,b数组按次序存入c数组,然后再把c数组的内容赋给a数组;我则是使用一个新数组将a,b中出现的数字在数组hash内计次,最后把hash内的数组下标赋值给a数组.
2.3 说反话-加强版
2.3.1 伪代码
ch[500100]
flag<-0
fgets ch
int *endp -> ch
while *endp != ' ' && *endp != '
'
do endp++
end while/*把指针移动到最后*/
while p != ch /*循环至字符串开头*/
do if *p != '.'
then len++
用flag控制空格并输出p
len<-0
end if
p--
end while
if *ch!=' '
then 用flag控制空格并输出p
return 0
2.3.2 代码截图
2.3.3 与超星视频的区别
我的代码是基于超星视频的思路编写的,所以除了一些小细节外几乎没有太大的区别.