0.展示PTA总分

1.本章学习总结

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

指针定义

指针指向的是一片内存地址:
一般用定义数据类型的符号 和‘*’ 来定义指针

int *p = &a;//定义指针p,取地址a 让p指向a。

指针相关运算

  • 指针变量加/减一个整数

例如:p++,p--,p+i等。
C语言与 C++语言规定,一个 指针变量加/减一个 整数是将该指针变量的原值(是一个地址)和它指向的变量所占用的内存单元 字节数相加或相减。这样就保证了p+i指向p下面的第i个元素。
如p+i代表这样的地址计算:p+i*d,其中d为p所指向的 变量单元所占用的 字节数。
指针变量赋值
C语言与C++语言规定,可以将一个 变量或一个函数的入口地址赋值给相应的指针变量。
例如(假设p是相应的指针):
p=&a;
p=max;(max为已经定义的函数)

  • 指针变量相减

如果两个 指针变量指向同一个 数组的元素,则两个指针变量之差是两个指针之间的元素个数。
注意, 指针变量相加无实际意义。

  • 指针变量比较

如果两个指针变量指向同一个数组的元素,则可以进行比较。指向前面元素的 指针变量小于指向后面元素的指针变量。

指针做函数参数

因为指针指向的是一片内存空间,所以用指针作为函数的参数,在函数体中,指针指向的形参的数改变了,那么指针指向的
那片内存空间的值也会随之改变,所以指针可用于需要函数体传回多个值的时候使用。

#include<stdio.h>
void fun(int* x)
{
	*x = 3;//此时a那片内存的值为3,即使函数fun结束,a的值也不会消失
}
int main()
{
	int a;
	int* p = &a;
	fun(&a);//也可以直接传入指向a的指针,即传入一个地址:
       // fun(p);
	return 0;
}

1.2 字符指针

1.2.1指针如何指向字符串

字符串可以由一个指针指向

const char *p = "hellow";

第一种直接用指针指向的无法改变其中的字符。
或者一个数组存放,指针指向该数组

char a[] = "hellow";
char *p = a;

用数组赋值的能更改其中的字符

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

  • strcpy
char *strcpy(char *strDest, const char *strSrc)
{
baichar *r = strDest;
while(*strDest++=*strSrc++);//把strSrc复制给strDest
*strDest = 0;
return r;
}
  • strlen
int strlen(const char* str)

{
    if (NULL == str)
        throw"Invalid Argument!";
    int len;
    for (len = 0; *str&&*str != '\n'; str++)//算出字符串的长度
        len++;
    return len;
}
  • strcat
char *strcat(char *strDest, const char *strScr) 
{
    char * address = strDest;
    if(!strDest||!strScr) return NULL;//防止传入空指针    
    while(*strDest)      
    {            
       strDest++;      //遍历字符串直到NULL  
    }            
    while(*strDest++ = *strScr++) //将strScr字符串连接到strDest之后
    {
       NULL;        
    }            
return address;        
}
  • strcmp
int strcmp( const  char* src,const  char* dst)
{
    int  ret = 0;

    while (!(ret = *(unsigned  char*)src - *(unsigned  char*)dst) && *dst)//逐个比较相对应的字符串的字符的大小
        ++src, ++dst;

    if (ret < 0)
        ret = -1;
    else  if (ret > 0)
        ret = 1;

    return(ret);
}

1.2.3字符串相关函数用法



1.3 指针做函数返回值

int *p()
{
reutrn p;//返回地址p
}

注意:
1.如果p在函数中作了位运算,则返回的是该指针做了位运算的地址所以,
一般需要在开始时定义一个指针指向p的首地址,然后返回该新定义的指针。
2.返回的指针所指的内容的生存周期因为全局变量,如果在函数中定义了一片内容,
然后返回指向该内容的指针则会报错。
3.返回的指针需要作为判断时,也可返回NULL

1.4 动态内存分配

1.4.1为什么要动态内存分配

  • 要用一片连续的内存,如数组时,则可以用多少申请多少,不需要一开始把数组定义很大,占用多余的空间。
  • 在函数中申请可延长该数据的生存周期,直到程序结束或者free。

1.4.2堆区和栈区区别

1、栈区(stack)
由编译器自动分配释放 ,存放函数的参数值,局部变量的值等,内存的分配是连续的,类似于平时我们所说的栈,如果还不清楚,那么就把它想成数组,它的内存分配是连续分配的,
即,所分配的内存是在一块连续的内存区域内.当我们声明变量时,那么编译器会自动接着当前栈区的结尾来分配内存.

2、堆区(heap)
一般由程序员分配释放, 若程序员不释放,程序结束时可能由操作系统回收.类似于链表,在内存中的分布不是连续的,它们是不同区域的内存块通过指针链接起来的.
一旦某一节点从链中断开,我们要人为的把所断开的节点从内存中释放.

1.4.3动态内存分配相关函数及用法

头文件 #include<stdlib.h>

+malloc

void * malloc (size_t size);

malloc的使用比较直接,一个成功的malloc调用返回分配的size大小的内存的指针。失败时返回NULL并将错误代码置为ENOMEM。
教材中经常出现的用法是将malloc返回的void指针进行强制内存转换然后赋给内存指针,其实是不必要的,在赋值时C语言是可以将void类型指针自动转换成对应的指针的。

  • calloc

void * calloc (size_t nr, size_t size);

calloc可以分配nr个size大小的内存空间,一般用于一组struct结构体的分配。
那么calloc和malloc有什么区别呢?抛开nr参数不谈(malloc也可以将参数设置为nr*size达到一样的效果),
最关键的区别是malloc分配的内存是不保证初始化的,而calloc会将分配的内存都初始化为0.

+relloc

void * realloc (void *ptr, size_t size);

realloc函数将ptr指向的内存空间重新分配大小为size并返回新的内存首地址。具体的实现,函数首先会尝试直接在已经分配的内存后进行padding,如果空间足够那么还是返回原来的地址,
如果不够,则会寻找新的空间并malloc size个字节,之后再将原先的内容“搬家”到新的内存地址,所以函数的返回值可能和原指针相同,也可能不同。
另外,size参数如果是0,则该函数和free效果相同。如果ptr是NULL,函数的效果和malloc相同~

注意用完这片内存后用free释放

void free (void *ptr);

释放前三个函数申请的内存空间。关于free最经典的问题就是内存泄露(memory leak)。所以,使用前三个分配函数分配的内存一定要记得free掉。

1.4.4 举例为多个字符串做动态内存要如何分配

char (*p)[10]
p = (char(*)[10])calloc(n,sizeof(char[10]))
char *a[10]
a = (char*)calloc(n,sizeof(char))

1.5 指针数组及其应用

  • 指针数组:用于存放字符指针的数组,仅用来存放指针,所以它指向的每个字符串的首地址均可以改变,
    由于指针指向一个地址,所以字符串的最大长度可以改变
char *p[n]//n为行的数量
  • 二维数组:二维数组本质上是两个一维数组的合成,定义时就已经分配给二维数组空间。

1.6 二级指针

即指向一个一级指针的地址指针

int **p;
int *a;
int n;
p = &a;//二级指针p指向一级指针a
a = &n;//一级指针a指向数n,则p最终也指向n的内容

1.7 行指针、列指针

行指针

等同于int (*p)[3]
则a为一个行指针,即a指向一个行的首地址,不指向其中的具体内容
可以用a来寻址各行的内容
或者移动到下一行p++

列指针

列指针与一个一级指针类似
即所指的是具体的内容
int a[3][3]
int *p =a[0]

2.PTA实验作业

2.1 7-5 删除字符串中的子串

2.1.1 伪代码

定义s和删除的del字符串
while(strstr(s,del)!=NULL)//重复寻找直至没有需要删除的字符串
  计算此时两个字符串的长度
  strcpy(temp,strstr(s,del))//将重复字符包括后面的字符串复制给temp
  计算temp的长度
  strcpy(s+len_s-loc,temp+len_del)/*s+s的长度到最后一个字符减去loc
  则到要删除的字符串的首地址,将temp+删除字符的长度,则为删去字符串后
  的字符串,复制到原字符串后面。*/
end while

2.1.2 代码截图

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


骆锟宏同学的代码是找到了子串然后进到函数进行一次删除,使指针的指向更清晰。

2.2 合并2个有序数组

2.2.1 伪代码

定义用来排序的数组c//用选择法或者冒泡法会超时
for 0 to m
c[a[i]]++
if(a[i]>max)a[i] = max 寻找最大值,在遍历c时有个上限
end if
end for
for 0 to n
和第一个for循环相同 遍历数组b,寻找最大值
for 0 to max
if(c[i]>0)
for 0 to c[i]
a[j] = i//将排序好的数存入a数组
end if
end for
end for

2.2.2 代码截图

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

林进源同学的代码是边比较边排序,少了许多循环,占用更少的内存,从最后面往前排序,也不会使原来的还未排序数被覆盖。

2.3 说反话-加强版

2.3.1 伪代码

定义str的长度len,i = len -1
while
  while(str[i]不为空格及i>=0时)
  i-- count ++
  end while
  if(count >=1)
    for 0 to count
    使a存放str的元素//将str的元素倒放过来
    end for 
  end if
  if(word ==1&&a[j-1] ==' ')
    a[j-1] = 0 //特殊判断,当仅有一个字母时 且前面都为空格
  end if

2.3.2 代码截图

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

大概思路相同,都是用if来判断处理各类特殊条件。

 posted on 2020-12-27 21:07    阅读(173)  评论(0编辑  收藏  举报