C博客作业05-指针

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

0.展示PTA总分(0----2)

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

1.1.1 资料查询

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

1.1.2 指针定义

C语言中,指针类型描述的是一个地址,这个地址指向内存中另外一个对象的位置。简单地说,指针表示的是它所指向对象的地址。

  • 定义:变量类型*变量名(char * ch;)
  • 其中变量名(ch)的值为指针地址,变量名(ch)才为指针地址中包含的值。
  • 定义多个指针变量时,每个指针变量前都必须加上*。

1.1.3 指针相关运算

  • 指针的运算优先级与正常变量不同就如ch++ !=(ch)++,前一个为地址自增,后一个为内容自增。写代码时要注意指针运算的优先级。
  • *表示取值的运算符,运算对象是地址; 运算的值是内容。
  • &表示取地址的运算符,运算对象是内容; 运算的值是地址。
  • ch=0 和 ch=NULL表示指向空地址。

1.1.4 指针做函数参数

void dete1(char *p,char *q)
{
   p=strstr(p,q);
   while(*(p+l)!='\0'){
   	*p=*(p+l);
   	*p++;
   }
   *p=*(p+l);
   return ;
}

其中传入的为指针的地址,在函数中运算时直接在地址中更改,在需要输出数组时更加简便,运算的速度更快。

1.2 字符指针

1.2.1 字符指针

  • 定义:指向字符型数据的指针变量。每个字符串在内存中都占用一段连续的存储空间,并有唯一确定的首地址。即将字符串的首地址赋值给字符指针,可让字符指针指向一个字符串。
  • 例:
char ch[]="hahahaha";
char *ch1=ch;

1.2.2 字符串相关函数及函数代码原型的理解

  • strcat( str1, str2) (连接str2到str1后面)
char *strcat( char *str1, const char *str2 )
{
	char *tempstr;
	tempstr=str1;
	if(!str1||!str2) return NULL;//防止空指针传入。否则程序奔溃。
	while(*str1)  str1++;
	while(*str2) {
		*str1=*str2;
		str1++;str2++;
	}
	*str1='\0'; 
	return tempstr;  //连接后字符串的的首地址。
}

定义局部变量tempstr来保存首地址,然后对str1和str2直接操作,通过指针将str2接到str1后面。

  • strcpy(strDest, strSrc) (将strSrc复制到strDest)
char *strcpy(char *strDest, const char *strSrc)  
{  
   assert((strDest != NULL) && (strSrc!= NULL)); 
    if (strDest == strSrc)  
        return strDest;  
    char *tempDest = strDest;  //保存首地址    
    while((*strDest++ = *strSrc++) != '\0');  //??
    *strDest=0;
    return tempDest;  
} 
  • strcmp(用于比较两个字符串)
#include "assert.h"  
int strcmp(const char *str1,const char *str2)  
{    int len = 0;  
     assert((str1!= NULL) && (str2 != NULL)); 
    while(*str1 && *str2 && (*str1==*str2))  
    {  
        str1++;  
        str2++;  
    }  
    if((*str1-*str2)>0)     
        return 1;  
    else if((*str1-*str2)<0)  
        return -1;  
    else  
        return 0;  
} 

对于大于等于小于三种情况分别输出1/0/-1。

1.2.3 字符串相关函数用法

<string.h>

  • strpbrk(str1,str2)
    char *strpbrk(const char *str1, const char *str2)
    检索字符串 str1 中第一个匹配字符串str2 中字符的字符

  • strrchr()
    char *strrchr(const char *str, int c)
    参数 str 所指向的字符串中搜索最后一次出现字符 c的位置。

  • strstr()
    char *strstr(const char *haystack, const char *needle)
    字符串 haystack 中查找第一次出现字符串 needle 的位置
    <ctype.h>

  • islower():如果 c 有相对应的小写字母,则该函数返回 c 的小写字母,否则 c 保持不变。

  • toupper():如果 c 有相对应的大写字母,则该函数返回 c 的大写字母,否则 c 保持不变。

  • isdigit():判断c是否是数字字符。

<stdlib.h>

  • atoi():该函数返回转换后的长整数,如果没有执行有效的转换,则返回零

1.3 指针做函数返回值

  • C语言允许函数的返回值是一个指针(地址),我们将这样的函数称为指针函数。
  • 用指针作为函数返回值时需要注意的一点是,函数运行结束后会销毁在它内部定义的所有局部数据,包括局部变量、局部数组和形式参数,函数返回的指针请尽量不要指向这些数据,C语言没有任何机制来保证这些数据会一直有效,它们在后续使用过程中可能会引发运行时错误。
  • 例:
    #include <stdio.h>
    #include <string.h>
    char *strlong(char *str1, char *str2){
        if(strlen(str1) >= strlen(str2)){
            return str1;
        }else{
            return str2;
        }
    }
    int main(){
        char str1[30], str2[30], *str;
        gets(str1);
        gets(str2);
        str = strlong(str1, str2);
        printf("Longer string: %s\n", str);
        return 0;
    }

1.4 动态内存分配

  • 指针是存储内存地址的变量。当我们声明了一个指针变量后,使用该指针时系统会根据指针内的地址索引内存块,读取内存内的值。指针因为是用来存地址的,所以一般固定长度为4个字节。void指针指向内存块的指针。
  • eg:
p=(int *)calloc(n,sizeof(int)))==NULL
  • 动态存储分配函数malloc( )
    void *malloc(unsigned size)
    再内存的动态存储中分配一连续空间,长度为size。申请成功,返回指向所分配内存空间的
    的起始地址的指针;否则返回NULL;
  • 计数动态存储分配函数calloc( )
    void *calloc(unsigned n,unsigned size)
    在内存的动态存储区中分配n个连续空间,每一存储空间的而长度为size,并且分配后还把存储块
    里全部初始化为0。申请成功,返回指向所分配内存空间的的起始地址的指针;否则返回NULL;
  • 动态存储释放函数free()
    viod free(void *ptr)
    盛放动态存储分配函数申请到的整块内存空间,ptr为指向要释放空间的首地址。
    释放后不允许再通过该指针去访问已经释放的块。
  • 分配调整函数realloc()
    void *realloc(void *ptr,unsigned size)
    更改以前的存储分配。ptr必须是以前通过动态存储分配得到的指针。参数size为现在
    需要的空间大小。分配失败,返回NULL;分配成功,返回一片能存放大小为siza的区块。

1.5 指针数组及其应用

在实现排序功能的时候,一般都是通过交换值的形式,通过循环逐渐得到我们想要的顺序。但是有时候排序通过值的交换实现起来比较麻烦,因此我们可以引用指针数组,通过交换地址的方式来得到我们想要的顺序。
例:

char a[4][10]={"CHINA","china","ABC","abcdef"}; // 将四个字符串通过从小到大的顺序依次排序,如果用交换值的形式,实现起来就会比较麻烦。但是通过指针数组实现起来就很容易。
char  *b[4]={a[0],a[1],a[2],a[3]};  // 定义一个指针数组分别依次指向字符数组

1.6 二级指针

  • 指针可以指向一份普通类型的数据,例如 int、double、char 等,也可以指向一份指针类型的数据,例如 int *、double *、char * 等。如果一个指针指向的是另外一个指针,我们就称它为二级指针,或者指向指针的指针。假设有一个 int 类型的变量 a,p1是指向 a 的指针变量,p2 又是指向 p1 的指针变量.
  • eg:
int a =100;
int *p1 = &a;
int **p2 = &p1;

1.7 行指针、列指针

  • 行指针
    常用的二维数组,如:
int a[3][5];

行指针是指向数组的指针,即上面几种指针类型中的 int (*a)[5];所以,当二维数组要被当做参数进行传递时

void funcByRowPtr(int (*p)[5],const int row);
//或
void funcByRowPtr(int p[][5],const int row);
写法 解释 指针类型
a+0或&a[0] 指向第1个一维数组的地址(指向第1行) 行指针
a+1或&a[1] 指向第2个一维数组的地址(指向第2行) 行指针
a+2或&a[2] 指向第3个一维数组的地址(指向第3行) 行指针
  • 列指针
写法 解释 指针类型
a[0]+0或&a[0][0] 指向第1行第1列的地址 列指针
a[0]+1或&a[0][1] 指向第1行第2列的地址 列指针
a[1]+0或&a[1][0] 指向第2行第1列的地址 列指针
a[1]+1或&a[1][1] 指向第2行第2列的地址 列指针
所以如果用列指针进行函数传参,可以直接声明如下:
void funcByColPtr(int * const colPtr,const int row,const int col);
  • 综上所述:对行指针解引用,可以得到列指针,对列指针解引用,可以得到具体的元素值:
    但是这并不表示行指针可以作为二级指针进行函数传参.

2.PTA实验作业(7分)

2.1 二分法查找(2分)

2.1.1 伪代码

设置下表常量max,min
while(min<=max)//判断min和max是否重合
{
      count的值自增;
      取中间数下标;
      判断输入值的大小;
      如果等于则return该下表;
}
return 非正数(-1)//不能有与下标重合的可能

2.1.2 代码截图


2.1.3 找一份同学代码(尽量找思路和自己差距较大同学代码)比较,说明各自代码特点。

都差不多。。。。。

2.2 合并2个有序数组(2分)

2.2.1 伪代码

定义动态指针p;
do
{
      if((n && *(a + i) > *(b + j)) || m == 0)//判断数组中某一元素的大小
      {
            *(p + i + j) = *(b + j);//将对应b的值赋给p
            j++;
            if (j == n)//找到a中比b中的数并将a中那几个数输入p中
            {
                for (; i + j < m + n; i++)//
                {
                    *(p + i + j) = *(a + i);
                }
            }
        }
        else//同上
        {
            *(p + i + j) = *(a + i);
            i++;
            if(i == m)
            {
                for (; i + j < m + n; j++)
                {
                    *(p + i + j) = *(b + j);
                }
            }
        }
    } while (i + j < m + n);//当所有数都输入完成时离开
}
将p中的数赋给a;

2.2.2 代码截图



2.2.3 找一份同学代码(尽量找思路和自己差距较大同学代码)比较,说明各自代码特点。

智康的代码:

我的代码是将啊a和b输入到另一个数组中,智康是从后往前输入,避免了数据的冲突,减少使用了一个指针有利于代码运算速度的提高

2.3 说反话-加强(3分)

2.3.1 伪代码

      for重最后一个往前数
      {
            do if 不为‘ ’;
            记录下标i;
            for向前遍历
            if遇到空格离开
            break;
       head=j+i;指向下一单词首字母
       if 如果不是输出第一个单词,即原字符串最后一个单词,要输出一个相隔的空格
       for(k=head; k<=real; k++)//从该单词的开头字符逐个输出到末尾字符
       count++;
       从遇到的空格那个位置开始,继续向前查询
      } 
      return 0;

2.3.2 代码截图



2.3.3 请说明和超星视频做法区别,各自优缺点。

在超星视频中使用了printf("%.*s,len,p")从len开始输出的输出方法。
视频中是在判断是否为最后一个数分两种情况输出,而我自己是对空格分开判断是否需要输出空格,我自己的方法优点是不需要再对第一个单词再次进行判断,而超星中的代码可以减少很多代码量。

posted @ 2020-12-27 22:55  2011王博  阅读(148)  评论(0编辑  收藏  举报