我的第六篇博客--指针

这个作业属于哪个班级 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 请说明和超星视频做法区别,各自优缺点。

原文地址:https://www.cnblogs.com/CHINATYY/p/14199132.html