指针
| 这个作业属于哪个班级 | C语言--网络2011/2012 |
| ---- | ---- | ---- |
| 这个作业的地址 | C博客作业05--指针 |
| 这个作业的目标 | 学习指针相关内容 |
| 姓名 | 吕以晴 |
0.展示PTA总分(0----2)
1.本章学习总结(3分)
🌙1.1 指针定义、指针相关运算、指针做函数参数。
⭐指针定义
指针也就是内存地址,指针变量是用来存放内存地址的变量,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。
· int* p --- p为指向一个整型数据(int型)的指针变量;
· int* p[n] --- 指针数组P由n个指向整型数据的指针元素组成,每个元素都是int*类型;
· int (*p)[n] --- p为指向含有n个元素的一维数组的指针变量,数组内元素均为int型;
· int (*P)() --- p为指向函数的指针,该函数返回一个整型值;
· int **P --- p是一个指针变量,它指向一个指向整型数据的指针变量。
· const char *color[i]=
⭐指针相关运算
-
指针变量加/减一个整数
p++,p--,p+i,p-i -
指针变量赋值
可以将一个变量或一个函数的入口地址赋值给相应的指针变量
p=&a(则将a的地址赋给p),p=NULL或p=0为空指针,p1=p2(将p2的值赋给p1)
-
指针变量相减
不是单纯的两个值相减,而是指两个指针之间的元素个数。(前提:两个指针变量指向同一个数组的元素) -
指针变量相加
没有实际意义 -
指针变量比较
指向前面元素的指针变量小于指向后面元素的指针变量(前提:两个指针变量指向同一个数组的元素)
⭐指针做函数参数
用指针变量作为函数参数, 在函数执行过程中使指针变量所指向的变量值发生变化,函数调用结束后,这些变量值的变化依然保留下来,这样就实现了”通过调用函数使变量的值发生了变化,在主调函数(如main函数)中使用这些改变了值”的目的.
用指针作函数参数可以将函数外部的地址传递到函数内部,使在函数内部可以对外部参数进行改变,并且这些参数的数据变化不会随着函数的结束而消亡。
void splitfloat(float x, int* intpart, float* fracpart)
{
*intpart = (int)x;
*fracpart = x - (*intpart);
}
此段函数用指针作函数参数,尽管没有返回值,但依旧达到了改变主函数内部变量的目的
🌙1.2 字符指针
⭐指针如何指向字符串
char *p;
char str[10] = "abcd";
p = str;
指针p指向字符串str的首地址,我们可以通过p++来移动指针的指向,从而进行运算
⭐字符串相关函数
以上函数只能用于字符串,不能用于字符
- tips:字符定义char str='a' 字符串赋值char str[]="a"
qsort()函数
使数组按从小到大的顺序重排。
- 头文件:#include <stdlib.h>
- 调用格式:qsort(str,strlen(str),sizeof(char/int),cmp)
一般使用qsort()函数要再写一个自定义函数cmp,来比较数组中相邻两个元素的大小,以达到从小到大排列的作用
int cmp(const void *a, const void *b)
{
return *((char *)a) - *((char *)b);
}
strtok()函数
将字符串分割成一个个片段
- 头文件:#include <string.h>
- 调用格式:char *strtok(char s[], const char *delim)
strtok()函数作用于字符串s,以包含在delim中的字符为分界符,将s切分成一个个子串。即若在字符串s中发现参数delim中包含的分割字符时,则会将该字符改为'\0' 字符。
strtok(str,"\n");
if(str)
printf("%s",str);
可以使用strtok()函数去除字符串末尾的"\n"
🌙1.3 指针做函数返回值
char *search(char *s, char *t)
{
int lens=strlen(s);//定义字符串s的长度
int lent=strlen(t);//定义子串t的长度
int i,j,k;
int x=lens-lent;//计算二者长度差值
for (i=0; i<=x; i++)
{
for (j=0,k=i; j<lent; j++,k++)
{
if (s[k]!=t[j])
break;
}
if (j==lent)
break;
}
if (i<=x)
return s+i;//满足条件,返回对应指针
else
return NULL;//不满足条件,返回空指针
}
-
tips1:指针返回时,注意不要返回局部定义的指针,会出现乱码
-
解决方法
① 用局部变量定义(static int/char...)
② 用堆定义而不用栈定义(mcollc)
③ 使用从主函数中引入的值来存放 -
tips2:指针返回时的类型要与函数定义时的类型保持一致
🌙1.4 动态内存分配
⭐堆区和栈区的区别
- 栈区:由系统自动分配,速度较快,用于存放函数的參数值,局部变量的值等但程序员是无法控制的。(只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。)
- 堆区:通过new、malloc、realloc分配的内存块,需要程序员主动进行释放,而平常所说内存泄也就发生在堆区。
⭐动态内存分配相关函数及用法
#include <stdlib.h>
int *p;
p=(int*)calloc(30240000,sizeof(int))//动态内存申请(前一个为个数n,第二个数为每个单元的空间)
for(i=0;i<;i++)
p[i]=2*i//下标法
for(i=0;i<;i++)
printf("%d",p[i]);
free(p);//申请后要释放,否则会产生内存碎片,影响程序效率
calloc()函数和malloc()函数返回值类型为void(*),赋给其他指针变量时,要强转
int *p;
p=(int*)calloc(n,sizeof(int));
⭐为多个字符串做动态内存要如何分配
char* p[MAXR];
char str[MAXC];
for (int i = 0; i < MAXR; i++)/*输入诗歌*/
{
gets(str);
p[i] = (char*)malloc(sizeof(str) + 1);
strcpy(p[i], str);
}
此部分为藏尾诗的部分代码,通过循环来对多个字符串进行动态内存分配
🌙1.5 指针数组及其应用
若要表示多个字符串:
·二维数组:char str[3][5]={"abc","bcd","cdef"};
·指针数组: char* str="abc"
- tips:二维数组字符数组名是常量,不能进行运算,不能改变值。而指针数组的指针变量的值是可以改变的,可以进行运算
eg:
char* str="abcd";
a++;
🌙1.6 二级指针
A(即B的地址)是指向指针的指针,称为二级指针
在如上的A指向B、B指向C的指向关系中,若A、B、C都是变量,即C是普通变量,B是一级指针变量,其中存放着C的地址,A是二级指针变量,其中存放着B的地址,B的值(即C的地址)是一级指针数据;A的值(即B的地址)是二级指针数据.
char *a[3]={"I","love","you"};
char **p=a;
printf("%s %c",*(p+1),*(*(a+2)+2));
这段代码的输出为 love u
🌙1.7 行指针、列指针
⭐定义格式
int (*p)[4]
行指针是指向数组的指针,指的是一整行,不指向具体元素。
格式 | 解释 | 指针类型 |
---|---|---|
a+0或&a[0] | 指向第1个一维数组的地址(即指向第一行) | 行指针 |
a+1或&a[1] | 指向第2个一维数组的地址(即指向第二行) | 行指针 |
a+2或&a[2] | 指向第3个一维数组的地址(即指向第三行) | 行指针 |
列指针是指向非常量的常量指针,指的是一行中某个具体元素。 | ||
---- | ---- | ---- |
a[0]+0或&a[0][0] | 指向第1行第1列的地址 | 列指针 |
a[1]+1或&a[1][1] | 指向第2行第2列的地址 | 列指针 |
a[1]+0或&a[1][0] | 指向第2行第1列的地址 | 列指针 |
a[2]+0或&a[2][0] | 指向第3行第1列的地址 | 列指针 |
⭐主要用法
用列指针输出二维数组
#include <stdio.h>
void main()
{
int a[3][3]={1,3,5,7,9,11,13,15,17};
int *p= a[0]; /*列指针*/
for(; p < a[0] + 9; p++)/*输出第一行*/
{
printf("%d ",*p);
}
return 0;
}
用行指针输出二维数组
#include <stdio.h>
void main()
{
int a[3][3]={1,3,5,7,9,11,13,15,17};
int (*p)[3]= &a[0]; /*行指针,也可写为int (*p)[4]= a;*/
int i, j;
for(i = 0; i < 3; i++)/*输出整个二维数组*/
{
for(j = 0; j < 3; j++)
{
printf("%d ",*(*(p + i) + j));
}
}
return 0;
}
- 对行指针解引用,可以得到列指针,对列指针解引用,可以得到具体的元素值。
🌙1.8 易错点及注意事项
- 指针一定要有指向
- p=&a;p++,先自增再,但p++=p(p=p+1,因为是后自增)所以p++=a;但自增后p的值变为p+1,不再指向a,p变为野指针
- NULL符号常量,值为0
- 空指针:p=0或p=NULL
- 形参是指针变量,实参一定要是地址。地址的加一是移动到下一个存储单元内,而不是单纯的数值相加。
- for(p=a;p<a+n;p++)---a为数组a[MAX]
- strlen()函数:计算\0前的字符串长度
- len=strlen(str)语句不要放在循环内重复
2.PTA实验作业(7分)
==🌙2.1 输出月份英文名 ==
⭐2.1.1 伪代码
⭐2.1.2 代码截图
⭐2.1.3 找一份同学代码(尽量找思路和自己差距较大同学代码)比较,说明各自代码特点。
该同学使用的是case分支的写法,程序上看起来更清晰易懂,但却也更为繁琐;而我直接使用了数组并加以定义,达到输出月份英文名的效果。
🌙2.2 合并2个有序数组
⭐2.2.1 伪代码
⭐2.2.2 代码截图
⭐2.2.3 找一份同学代码(尽量找思路和自己差距较大同学代码)比较,说明各自代码特点。
该同学与我的做法大体相同,但在变量的设计上不够完备,首先变量名的设置上不够清晰,没有正确使用命名法,其次,他比我多设置了一个变量(而本来是可以不用的),程序更加繁琐了
🌙2.3 说反话-加强版
⭐2.2.1 伪代码
⭐2.3.2 代码截图
⭐2.3.3 请说明和超星视频做法区别,各自优缺点。
超星的做法更为清晰简洁
- 超星使用了while (endP&&endP!='\n')来去掉末尾的"\n"
- 超星使用了printf("%.*s",len,str)从len开始输出,使程序更加便捷