C博客作业05-指针

| 这个作业属于哪个班级 | C语言--网络2011/2012 |
| ---- | ---- | ---- |
| 这个作业的地址 | C语言博客作业05--指针 |
| 这个作业的目标 | 学习指针相关内容 |
| 姓名 | 韩龙飞 |

0.展示PTA总分

1.本章学习总结

1.1 指针定义、指针相关运算、指针做函数参数

※为何使用指针

通常,管理大量数据的有效方法不是直接处理数据本身,而是使用指向数据的指针。例如,如果需要对大量的大型记录进行排序,对指向该记录的指针列表进行排序效率要比直接对记录排序高得多,因为这样无需在内存中移动数据。

1.指针的定义

  • 假设变量p位于2000单元,该单元中存放变量x的地址1000,若取出变量p的值1000就可以访问内存1000单元,实现对变量x的操作,也就是通过p间接访问变量x。这种专门用来存放变量地址的变量是指针。

  • 一般形式:类型名 *指针变量名

  • 当指针声明符*在定义指针变量时被使用,说明被定义的变量是指针。

  • 星号不是运算符,故想要对指针做处理时,前面不需要带*

  • 定义多个指针变量时,每个指针变量前都必须加上*。

2.指针相关运算

①取地址运算和间接访问运算

int* p,a=3;
p=&a;

将整型变量a的地址赋给整型指针p,使指针p指向变量a。也就是说用取地址符&取变量a的地址,并将该地址值作为p的值,使p指向a。
指针的类型和它所指的类型需要相同。

②赋值运算

int a=3,*p1,*p2;
p1=&a;
p2=p1;

将a的地址给p1,再将p1的值给p2,所以指针p1与p2都指向a,即p1=p2=a。

③指针间的加减运算
一个指针加上一个整数代表着,访问在当前指针所指的位置挪动整数个位置后的数。
星号与自增自减优先级相同,但因为结合方向是从右到左,所以需要注意*p++(*p)++的区别。前者是指针移动后的元值,后者是当前指针所指元素增一后的结果。

④赋值
指针变量要先赋值再使用。为了避免引用为赋值的指针所造成的危害,在定义指针时,可先将它的初值置为空,不能用数值作为指针变量的初值。
对指针p进行赋值p=0;和p=NULL都表示指针p为空指针,空指针不指向任何一个单元

3.指针做函数参数

    void Swap1(int *p, int *q)
    {
        int buf;
        buf = *p;
        *p = *q;
        *q = buf;
        return;
    }
    void Swap2(int a, int b)
    {
        int buf;
        buf = a;
        a = b;
        b = buf;
        return;
    }

函数swap2不能进行数值的交换,因为当返回主调函数后,函数中的定义全部消亡,并没有将交换后的值传回实参。
而函数swap1中p指向a,q指向b,在改变*p的值后,就改变了该存储单元的内容,因此在函数中调换*p*q的数值,主调函数的a、b也相应发生了变化。

1.2 字符指针

①字符指针:指向字符型数据的指针变量。每个字符串在内存中都占用一段连续的存储空间,并有唯一确定的首地址。即将字符串的首地址赋值给字符指针,可让字符指针指向一个字符串

char *ptr = "Hello";//将保存在常量存储区的"Hello"的首地址赋值给ptr
与
char *ptr;
ptr = "Hello";//是等价的,注意不能理解为将字符串赋值给ptr

char str[10] = "Hello";
char *ptr = str;//数组名代表数组的首地址
/*等价于*/
 char *ptr;
 ptr = str;//等价于ptr = &str[0];将数组的首地址赋给字符指针ptr

④对于数组名str,不能使用str++操作使其指向字符串中的某个字符,因为数组名是一个地址常量,其值是不能被改变的。

*(ptr+i):字符串中第i+1个字符,相当于*(str+i),即str[i]
也可以用ptr++,移动指针ptr,使ptr指向字符中的某个字符

⑤字符串的长度(指字符串所含的字符个数,但不包括最后的’\0’)与字符数组的大小(指字符串所包含的字符个数加上’\0’,故+1)不一样。

for(i = 0;str[i] != '\0'; i++ )
{
     printf("%c",str[i]);//常用借助字符串结束标志'\0'识别字符串的结束
}
scanf("%s",str);//表示读入一个字符串,直到遇到空白字符(空格、回车符、制表符)为止,如果输入带有空格的字符串,只会读到空格以前而空格以后不会读入
printf("%s",str);//表示输出一个字符串,直到遇到字符串结束标志'\0'为止(注意这里可以带有空格输出)

※常用的字符串处理函数

1.3 指针做函数返回值

函数的返回值是一个指针(地址),这样的函数称为指针函数。
用指针作为函数返回值时需要注意的一点是,函数运行结束后会销毁在它内部定义的所有局部数据,包括局部变量、局部数组和形式参数,函数返回的指针尽量不要指向这些数据,不然它们在后续使用过程中可能会引发运行时错误。
指针做函数返回值有一个好处,就是它可以返回多个值到主调函数当中去。

1.4 动态内存分配

一般情况下,运行中的很多存储要求在写程序时无法确定,因此需要在运行的实际需求中分配合适的存储区。

  • 1.从栈区(stack)上分配
    • 在执行函数调用时,系统在栈上为函数内的局部变量及形参分配内存,函数执行结束时自动释放这些内存。
  • 2.从堆区(heap)上分配
    • 在程序运行期间,用动态内存分配函数来申请的内存都是从堆上分配的,动态内存的生存期由程序员决定。
/*动态存储分配函数*/
void *malloc(unsigned size)//动态存储分配函数
//功能:在内存的动态存储区中分配一连续空间,其长度为size。申请成功,则返回指向所分配内存空间的起始地址指针;失败,则返回NULL。
void *calloc(unsigned n,unsigned size)//计数动态储存分配函数
//功能:在内存的动态存储区中分配n个连续空间,每一个存储空间的长度为size,分配后把存储块全部初始化为0。申请成功,则返回指向所分配内存空间的起始地址指针;失败,则返回NULL。
void free(void *ptr)//动态存储释放函数
//功能:释放由动态存储分配函数申请到的整块内存空间。
void *realloc(void *ptr.unsigned size)//分配调整函数
//功能:更改以前的存储分配。
/*动态分配n个整型大小的空间*/
if((p=(int *)malloc(n*sizeof(int)))==NULL)
{
    printf("NOT able to allocate memory\n");
    exix(1);
}

1.5 指针数组及其应用

  • 1.定义

    • 一般形式类型名 *数组名[数组长度];

    • 指针数组中的每个元素都是指针类型,用于存放内存地址。

  • 2 多个字符串用二维数组表示和用指针数组表示区别

    • 二维字符数组一旦定义,那么每个字符串的最大长度、首地址都不能改变了

    • 字符指针数组是存放字符指针的数组。由于它仅用来存放指针,所以它指向的每个字符串的首地址可以改变,字符串最大长度也可以改变。

  • 举例:

char str[5][5]={"abc","abcd","aaaa","ad","k"};
str[0]到str[4]五个字符串的最大长度被限为(5-1)=4,注意处理字符串时不应溢出。由于每个字符串的地址已经确定,所以str[0]="news";是不允许的
而
char* str[5];
str[0]="Welcome!";
可以

1.6 二级指针

二级指针的概念

一般形式:类型名 **变量名;

若定义整型变量a=10,*p=&a,**pp=&p,则*p==**pp==a以此类推三级、四级……

1.7 行指针、列指针

使用行指针或者列指针可以指定到字符串中的某个字符。

行指针:一般形式:类型名 (*变量名)[数组长度]

列指针:一般形式:类型名 [数组长度](*变量名)

使用例:

char color[5][10] = { "red","blue","yellow","green","black" };
char (*pc)[10];
pc = color;
printf("%s\n", *(pc + 1));
printf("%c\n",*(*(pc+1)+2));

结果:

blue
u

2.PTA实验作业

2.1 删除字符串中的子串(https://pintia.cn/problem-sets/1333954783207010304/problems/1333954910390890510)

2.1.1 伪代码

定义字符数组s[1000]、t[1000]、q[1000]
定义字符变量x

输入字符串s
输入字符串t

定义整形变量lens=s的字符串长度
定义整形变量lent=t的字符串长度
定义字符指针p

while(p=strstr(s,t))//找到子串首字符在字符串中的地址
    do while(*(p+lent)!='\0')//字符前移
	do 令字符前移至遍历自子串首字符位置之后的字符串到结束符
    end while
    删除已前移的多余字符
end while
输出字符串s

2.1.2 代码截图

2.1.3同学代码

在函数的调用上,该同学利用了strcat函数,直接完成了在删除子串后的后续字符串的前移,十分的简便,运行耗时也很少。

反观我的代码,我利用的是每次单个字符的前移,这大大的增加了计算机的运算量,而且代码可读性不高(我看自己的是这样的)

2.2 合并2个有序数组(https://pintia.cn/problem-sets/1333954783207010304/problems/1333954910390890504)

2.2.1 伪代码

merge(指针a, 整型变量m, 指针b, 整型变量n)/*用于归纳并排序的函数*/
定义整型变量i, j, k, temp均为0
定义整型指针p = a
while i<m&&j<n
	if *a>=*b
	        then a[k]=*b
		     b++
		     j++
		     k++
	        else a[k]=*p
		     p++
		     i++
		     k++
	end if
end while
if i<m
	while k<=m+n-1
		do a[k]=*p
		   p++
		   k++
	end while
end if
if j<n
	while k<=n+m-1
		then a[k]=*b
		     b++
		     k++
	end while
end if
for i=1 to m+n-1
    do for j=i+1 to m+n-1
		do if a[i]>a[j]
			   then temp=a[i]
			        a[i]=a[j]
			        a[j]=temp
		   end if
	   end for
end for
printArray(指针arr, 整型变量arr_size)/*用于输出的函数*/
定义整型变量i
for i=0 to arr_size-1
    if i=0
	  then 输出arr[i](不带空格)
	  else 输出 arr[i](带空格)
    end if
end for

2.2.2 代码截图

2.2.3同学代码

同学的代码利用另一个指针来存储两个数组,在没有归到一起之前就进行了排序,并且利用了动态内存分配,防止溢出。但二级指针在这里定义之后没有任何意义。

我则是先将两个数组放到一起再进行排序,而且整合的过程十分复杂,导致变得十分繁琐。(脑死状态下写的果然都没法看)

更改后

2.3 说反话-加强版(https://pintia.cn/problem-sets/1333954783207010304/problems/1333954910390890509)

2.3.1 伪代码

定义字符数组a
定义指针p、q分别用来存储字符串a的首地址和尾地址
定义整型变量flag用来判断输出条件
输入字符串a
令p的指针指向a的首字符
while(*p!='\n'&&*p!='\0')
    do p++
	end while
令q的指针指向a字符串尾字母
while(q!=a)
    do if (*q==' ')
		then if (* (q + 1) != ' ' && *(q + 1) != '\0')
		      then if (flag==1)
		            then 输出q+1后的字符串
		                 令flag=0
			  else 输出q后的字符串
		      end if
		*q='\0'
		end if
	end if
    q--
end while
if (*a!=' ')
    then if (flag == 1)
        then 输出q + 1后的字符串
        令flag = 0
    else 输出q后的字符串
	end if
end if

2.3.2 代码截图

2.3.3和超星视频做法区别

超星视频里的做法用了一种没见过的输出方式,即printf("%.*s,len,p"),可以从某个地址开始子串,但具体用法还是不是很熟悉。

视频中考虑了空格的输出,而我的方式则不用再在输出中加空格,可以直接利用句子中的空格。除了这里不大相同以外其他地方基本相同。

我借鉴了视频中的逆向输出的方法,代码量减少了很多,这是我需要学习的地方。

※知识点
逆向扫描字符:while(p!=beginPtr) {p--}
字符串指针表示字符串:printf("%.s",len,str);
利用不同的指针指向所需的地址效率更高。

posted @ 2020-12-27 14:57  箱推人  阅读(166)  评论(0编辑  收藏  举报