这个作业属于哪个班级 | C语言--网络2011/2012 |
---|---|
这个作业的地址 | C博客作业05--指针(https://i.cnblogs.com/posts/edit) |
这个作业的目标 | 学习指针相关内容 |
姓名 | 唐宇悦 |
0.展示PTA总分
1.本章学习总结
1.1 指针定义、指针相关运算、指针做函数参数。
指针定义:类型名 *指针变量名
例如:
-
int *s是指向整型变量的指针变量
-
float *d是指向浮点变量的指针变量
-
char *g;是指向字符变量的指针变量
注意一个指针变量只能指向同类型的变量
定义多个指针变量时,每一个指针变量前面必须加上
指针变量必须赋值后才能使用
指针相关运算
通过取地址运算符&和间接访问运算符*完成
如:int *p,a=3;
p=&a
表示将整形变量a的地址赋给整形指针p,使指针p指向变量a。
指针的类型和它所指向变量的类型必须相同
-
指针 +/- 整数 = 指针所对应的内存空间与它所指向的类型乘以整数相加减。eg. p++ --> p = p + 1
-
指针 - 指针 = 两个指针相差的数据个数。
-
指针的比较:如果两个指针变量指向同一个数组的元素,那么指向前面元素的指针变量小于指向后面元素的指针变量。
-
指针加指针没有实际意义
指针做函数参数
如:交换两个变量的普通做法
void swap(int a, int b)
{
int temp; //临时变量
temp = a;
a = b;
b = temp;
}
int main()
{
int a = 66, b = 99;
swap(a, b);
printf("a = %d, b = %d
", a, b);
return 0;
}
但是运行后发现a,b的值并未交换,这是因为 swap() 函数内部的 a、b 和 main() 函数内部的 a、b 是不同的变量,占用不同的内存,它们除了名字一样,没有其他任何关系,swap() 交换的是它内部 a、b 的值,不会影响它外部(main() 内部) a、b 的值。
所以改用指针变量作函数参数后就可轻松解决这个问题
void swap(int *p1, int *p2){
int temp; //临时变量
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int main(){
int a = 66, b = 99;
swap(&a, &b);
printf("a = %d, b = %d
", a, b);
return 0;
}
调用 swap() 函数时,将变量 a、b 的地址分别赋值给 p1、p2,这样 p1、p2 代表的就是变量 a、b 本身,交换 p1、p2 的值也就是交换 a、b 的值。函数运行结束后虽然会将 p1、p2 销毁,但它对外部 a、b 造成的影响是“持久化”的,不会随着函数的结束而“恢复原样”。
需要注意的是临时变量 temp,它的作用特别重要,因为执行*p1 = *p2;语句后 a 的值会被 b 的值覆盖,如果不先将 a 的值保存起来以后就找不到了
1.2 字符指针
定义:指向字符型数据的指针变量,每个字符串在内存中都占用一段连续的存储空间,并有唯一确定的首地址。即将字符串的首地址赋值给字符指针,可让字符指针指向一个字符串。
字符串相关函数
strlen()
计算字符串s的长度
strcmp
int strcmp (const char* str1,const char* str2)
功能:字符串比较
返回值:若参数s1和s2字符串相同则返回0,s1若大于s2则返回大于0的值,s1若小于s2则返回小于0的值
字符串复制函数:strcpy
1.3 指针做函数返回值
函数返回值必须用同类型的变量来接受,也就是说,返回值为指针值的函数的返回值必须赋值给同类型的指针变量。
1.4 动态内存分配
- 首先为什么要动态分配内存
1:因为内存太宝贵。
2:如果全部是静止内存不能释放,对于小的程序可以运行完毕。但是对于大的程序,还没运行完,内存就要被占用完,此时就要发生内存泄露。
3:给定一个占用内存可变大小的变量(假设是数组的长度len),给该变量通过函数动态分配内存后,分配内存的大小是根据数组的长度len决定的,假定用户输入len的大小是5,系统就会动态的给该数组分配长度为5的内存,该段代码运行结束后,系统调用free()函数释放分配的内存,然后接着运行剩下的程序。换句话说,动态分配内存可以根据需要去申请内存,用完后就还回去,让需要的程序用。
1.malloc()
void * malloc(size_t size)
1).malloc()函数会向堆中申请一片连续的可用内存空间
2).若申请成功 ,,返回指向这片内存空间的指针 ,若失败 ,则会返回NULL, 所以我们在用malloc()函数开辟动态内存之后, 一定要判断函数返回值是否为NULL.
3).返回值的类型为void * 型, malloc()函数并不知道连续开辟的size个字节是存储什么类型数据的 ,所以需要我们自行决定 ,方法是在malloc()前加强制转 ,转化成我们所需类型 ,如:
(int)malloc(sizeof(int)n).
4).如果size为0, 此行为是未定义的, 会发生未知错误, 取决于编译器
例如:
int *p = NULL;
int n = 0;
scanf("%d", &n);
p = (int*)malloc(sizeof(int) * n);
if(p != NULL){
//....需要进行的操作
}
2.free()
void free(void* ptr)
在堆中申请的内存空间不会像在栈中存储的局部变量一样 ,函数调用完会自动释放内存 , 如果我们不手动释放, 直到程序运行结束才会释放, 这样就可能会造成内存泄漏, 即堆中这片内存中的数据已经不再使用, 但它一直占着这片空间, (通俗说就是就是占着茅坑不拉屎), 所以当我们申请的动态内存不再使用时 ,一定要及时释放 .
1).如果ptr没有指向使用动态内存分配函数分配的内存空间,则会导致未定义的行为.
2).如果ptr是空指针,则该函数不执行任何操作。
3).此函数不会更改ptr本身的值,因此它仍指向相同(现在已经无效)的位置(内存)
4).在free()函数之后需要将ptr再置空 ,即ptr = NULL;如果不将ptr置空的话 ,后面程序如果再通过ptr会访问到已经释放过无效的或者已经被回收再利用的内存, 为保证程序的健壮性, 一般我们都要写ptr = NULL
注意 : free()不能重复释放一块内存, 如:
free(ptr);
free(ptr);
这个是错的, 已经释放过的内存不能重复释放, 会出现内存错误 .
free()具体用法, 举个例子 :
int *p = NULL;
int n = 0;
scanf("%d", &n);
p = (int*)malloc(sizeof(int) * n);
if(p != NULL){
//....需要进行的操作
}
//操作完成 ,不再使用这片内存空间
free(p);
p = NULL;
堆区和栈区区别。
1)栈(satck):由系统自动分配。例如,声明在函数中一个局部变量int b;系统自动在栈中为b开辟空间。
(2)堆(heap):需程序员自己申请(调用malloc,realloc,calloc),并指明大小,并由程序员进行释放。
1.5 指针数组及其应用
在实现排序功能的时候,一般都是通过交换值的形式,通过循环逐渐得到我们想要的顺序。但是有时候排序通过值的交换实现起来比较麻烦,因此我们可以引用指针数组,通过交换地址的方式来得到我们想要的顺序。
例:char a[4][10]={"CHINA","china","ABC","abcdef"} 将四个字符串通过从小到大的顺序依次排序,如果用交换值的形式,实现起来就会比较麻烦。但是通过指针数组实现起来就很容易。
char *b[4]={a[0],a[1],a[2],a[3]} 定义一个指针数组分别依次指向字符数组,如下图所示
通过交换指针地址来实现从小到大的排序,指针数组b[0],指向的是最小字符串,b[3]指向最大字符串,如图所示:
1.6 二级指针
二级指针也是一个变量,它指向的一定是“指针的地址”。对比下,一级指针指向的是普通变量的地址,二级指针指向的是“一级指针的地址”,以此类推,三级指针对应的是“二级指针的地址”。举例代码如下:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
//定义普通变量、一级指针、二级指针,不初始化
int a;
int *p1;
int **p2;
//对前面的普通指针、一级指针、二级指针进行初始化赋值
a = 10;
p1 = &a;
p2 = &p1;
printf("a = %d
", a);
printf("&a = %d
", &a);
printf("p1 = %d
", p1);
printf("*p1 = %d
", *p1);
printf("p2 = %d
", p2);
printf("*p2 = %d
", *p2);
printf("**p2 = %d
", **p2);
printf("&p2 = %d
", &p2);
return 0;
}
1.7 行指针、列指针
-
行指针:指向某一行,不指向具体的元素。
-
列指针:指向行中具体的元素。
也就是说,列指针只要在同一行,不管它们指向行中的哪个元素,它们的行地址都是在同一行的地址,所以它们的行地址都是一样的。
所以,
&列指针--->行指针
相反地可以推出:
*行指针---->列指针
2.PTA实验作业
2.1
字符串反正序连接
2.1.2 代码截图
2.1.3 找一份同学代码(尽量找思路和自己差距较大同学代码)比较,说明各自代码特点。
同学的代码调用了strlen函数减少了很多繁琐的部分,比较起来更通俗易懂且可读性强。
2.2 题目名2
合并2个有序数组
2.2.2 代码截图
2.3 题目名3
说反话-加强版
2.3.2 代码截图
2.3.3 请说明和超星视频做法区别,各自优缺点。