zoukankan      html  css  js  c++  java
  • 指针

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

    1.本章学习总结(3分)

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

    1. 指针是变量,但是指针的字节长度是固定的。因为指针保存的是地址,由操作系统的位数决定,32位机的字节是4,64位机的字节是8。
    2. 指针指向的内存空间和对应的内存空间

      在这里定义了一个整型指针p保存num的地址(0x1000),num的地址就是首字节的地址,而指针p本身的地址为0x2000。引入指针的定义:
      num对应的内存空间为5,指针p对应的内存空间为0x1000,指针指向的内存空间为5。
      num++:对num对应的内存空间加1。 5 --> 6
      p++:对p对应的内存空间加1。(步长) 0x1000 --> 0x1004
      (p)++:对p指向的内存空间加1。其中p是根据p对应的内存空间找到其对应的内存空间。 5 --> 6
      等式:
      p == &num
      *p == num == *(&num)
    3. 指针的运算
      a. 指针 +/- 整数 = 指针所对应的内存空间与它所指向的类型乘以整数相加减。eg. p++ --> p = p + 1
      b. 指针 - 指针 = 两个指针相差的数据个数。
      c. 指针的比较:如果两个指针变量指向同一个数组的元素,那么指向前面元素的指针变量小于指向后面元素的指针变量。
    4. 指针做函数参数
      函数指针可以作为一个参数传递给另一个函数。这时函数指针的使用就像普通的常量和变量一样。当函数指针作为参数传递的时候,这时接收参数传递的函数通常需要根据这个指针调用这个函数。
    int calculate(int a, int b, fun_t operation)
    {
     int result;
     result = operation(a, b); // 运算
     return result;
    }
    

    其中,fun_t是一个函数指针,其定义为:

    typedef int (*fun_t)(int, int);
    
    该函数指针fun_t指向一个带两个int类型的形参、int类型的返回值的函数。使用关键字typedef对int (*)(int, int)进行重命名(封装)为fun_t.
    

    1.2 字符指针

    1. 除了字符数组,C语言还支持另外一种表示字符串的方法,就是直接使用一个指针指向字符串,例如:
      ``
      char *str = "http://c.biancheng.net";
    或者:
    

    char *str;
    str = "http://c.biancheng.net";

    字符串中的所有字符在内存中是连续排列的,str 指向的是字符串的第 0 个字符;我们通常将第 0  个字符的地址称为字符串的首地址。字符串中每个字符的类型都是char,所以 str 的类型也必须是char *。
    2. 字符串相关函数
    

    函数名: stpcpy
    功 能: 拷贝一个字符串到另一个
    用 法: char *stpcpy(char *destin, char *source);

    函数名: strcat
    功 能: 字符串拼接函数
    用 法: char *strcat(char *destin, char *source);

    函数名: strchr
    功 能: 在一个串中查找给定字符的第一个匹配之处
    用 法: char *strchr(char *str, char c);

    函数名: strcmp
    功 能: 串比较
    用 法: int strcmp(char *str1, char *str2);
    看Asic码,str1>str2,返回值 > 0;两串相等,返回0

    函数名: strncmpi
    功 能: 将一个串中的一部分与另一个串比较, 不管大小写
    用 法: int strncmpi(char *str1, char *str2, unsigned maxlen);

    函数名: strcpy
    功 能: 串拷贝
    用 法: char *strcpy(char *str1, char *str2);

    函数名: strcspn
    功 能: 在串中查找第一个给定字符集内容的段
    用 法: int strcspn(char *str1, char *str2);

    函数名: strnset
    功 能: 将一个串中的所有字符都设为指定字符
    用 法: char *strnset(char *str, char ch, unsigned n);

    函数名: strdup 
    功  能: 将串拷贝到新建的位置处 
    用  法: char *strdup(char *str); 
    
    函数名: strerror 
    功  能: 返回指向错误信息字符串的指针 
    用  法: char *strerror(int errnum); 
    
    函数名: strstr 
    功  能: 在串中查找指定字符串的第一次出现 
    用  法: char *strstr(char *str1, char *str2); 
    

    1.3 指针做函数返回值

    用指针作为函数返回值时需要注意的是,函数运行结束后会销毁在它内部定义的所有局部数据,包括局部变量、局部数组和形式参数,函数返回的指针请尽量不要指向这些数据,C语言没有任何机制来保证这些数据会一直有效,它们在后续使用过程中可能会引发运行时错误。

    1.4 动态内存分配

    1. 为什么要动态内存分配
      a. 因为内存太宝贵。
      b. 如果全部是静止内存不能释放,对于小的程序可以运行完毕。但是对于大的程序,还没运行完,内存就要被占用完,此时就要发生内存泄露。
      c. 给定一个占用内存可变大小的变量(假设是数组的长度len),给该变量通过函数动态分配内存后,分配内存的大小是根据数组的长度len决定的,假定用户输入len的大小是5,系统就会动态的给该数组分配长度为5的内存,该段代码运行结束后,系统调用free()函数释放分配的内存,然后接着运行剩下的程序。换句话说,动态分配内存可以根据需要去申请内存,用完后就还回去,让需要的程序用。
    2. 堆区和栈区区别
      a. 在数据结构中,栈是一种可以实现“先进后出”(或者称为“后进先出”)的存储结构。假设给定栈 S=(a0,a1,…,an-1),则称 a0 为栈底,an-1 为栈顶。进栈则按照 a0,a1,…,an-1 的顺序进行进栈;而出栈的顺序则需要反过来,按照“后存放的先取,先存放的后取”的原则进行,则 an-1 先退出栈,然后 an-2 才能够退出,最后再退出 a0。
      在实际编程中,可以通过两种方式来实现:使用数组的形式来实现栈,这种栈也称为静态栈;使用链表的形式来实现栈,这种栈也称为动态栈。
      相对于栈的“先进后出”特性,堆则是一种经过排序的树形数据结构,常用来实现优先队列等。
      b. 内存分配中的栈与堆主要存在如下区别。
      分配与释放方式
      栈内存是由编译器自动分配与释放的,它有两种分配方式:静态分配和动态分配。
      1>. 静态分配是由编译器自动完成的,如局部变量的分配(即在一个函数中声明一个 int 类型的变量i时,编译器就会自动开辟一块内存以存放变量 i)。与此同时,其生存周期也只在函数的运行过程中,在运行后就释放,并不可以再次访问。
      2>. 动态分配由 alloca 函数进行分配,但是栈的动态分配与堆是不同的,它的动态分配是由编译器进行释放,无需任何手工实现。值得注意的是,虽然用 alloca 函数可以实现栈内存的动态分配,但 alloca 函数的可移植性很差,而且在没有传统堆栈的机器上很难实现。因此,不宜使用于广泛移植的程序中。当然,完全可以使用 C99 中的变长数组来替代 alloca 函数。
      而堆内存则不相同,它完全是由程序员手动申请与释放的,程序在运行的时候由程序员使用内存分配函数(如 malloc 函数)来申请任意多少的内存,使用完再由程序员自己负责使用内存释放函数(如 free 函数)释放内存,如代码所示:
    /*分配堆内存*/
    char  *p1 = (char *)malloc(4);
    … …
    /*释放堆内存*/
    free(p1);
    p1=NULL;
    

    对栈内存的自动释放而言,虽然堆上的数据只要程序员不释放空间就可以一直访问,但是,如果一旦忘记了释放堆内存,那么将会造成内存泄漏,导致程序出现致命的潜在错误。
    3. 动态分配相关函数及其用法
    1>. malloc:
    原型:void *malloc(int byte_size);
    作用:动态开辟byte_size个字节的内存空间,不进行初始化,返回指向此内存的指针
    举例:int p=(int )malloc(5sizeof(int));
    例解:动态开辟5
    4=20个字节大小的空间,返回空间首地址指针并强转为int *型后赋予指针变量p。
    注意:malloc只开辟空间,不初始化,即只将此空间由未占用状态变为已占用状态,空间内存储的具体数据未指定改变。函数返回值是空间首地址,上例中赋给了p变量。
    2>. calloc:
    原型:void calloc(int n,int type_byte_size);
    作用:动态开辟n
    type_byte_size个字节,将每个字节均初始化为ascii码0,返回指向此内存的指针,
    举例:int *p=(int )calloc(5,sizeof(int));
    例解:动态开辟5
    4=20个字节大小的空间,其中每个字节均赋初值0,返回空间首地址指针并强转为int *型后赋予指针变量p。
    注意:calloc在malloc的基础上将空间按字节初始化为ascii码0,且其参数有两个,两参数之积为空间总字节数。
    3>. realloc
    void * realloc(void * ptr,size_t size)
    realloc()函数让动态内存管理更加灵活 .在程序运行过程中动态分配内存大小, 如果分配的太大 ,则浪费空间, 如果太小, 可能还是会出现不够用的情况 .为了合理的利用内存,我们一定会对内存的大小做灵活的调整。那realloc() 函数就可以做到对动态开辟内存大小的调整(既可以往大调整, 也可以往小了调整) .
    1). ptr为需要调整的内存地址
    2). size为调整后需要的大小(字节数)
    3). 若调整成功, 返回值为调整大小后内存的起始位置(也就是指向调整后内存的指针), 若失败(当没有内存可以分配时, 一般不会出现), 则返回NULL, 所以还是要对返回值判空
    4). 如果ptr是空指针, 则和calloc()函数一样作用一样

    1.5 指针数组及其应用

    二维字符数组一旦定义,那么每个字符串的最大长度、首地址都不能改变了。
    字符指针数组,它是存放字符指针的数组。由于它仅用来存放指针,所以它指向的每个字符串的首地址可以改变,字符串最大长度也可以改变。
    相比而言,字符指针数组更灵活一些。
    例:

    二维字符数组:
    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 二级指针

    1.7 行指针、列指针

    (1). 行指针:指向某一行,不指向具体的元素。
    (2). 列指针: 指向行中具体的元素。
    从根本类型bai上讲:行指针是du int()[]类型,zhi列指针是int * 类型的。
    int a[2][3];定义它zhuan的行指针shu就是int(
    pr)[3]=a;而定义列指针int *pc=pr[0];
    pr,pr+1,pr+2分别表示第一二三行(其实就是&a[0],&a[1],&a[2])。
    至于列指针就是指向具体某行某列的指针。
    所谓行指针,就是一个指向一维数组的指针(它指向地址的值也是指针,每次自增跨度是一个数组的长度)。
    而列指针,就是指向具体某行某列的一个指针,指向地址的值是一个数组的元素。

    2.PTA实验作业(7分)

    2.1 题目名1(2分)


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

    char *search( char *s, char *t )
    {
    	int i=0,k=0;
    	int slen=0,tlen=0;
    	while(s[slen]!='') slen++; //计算s的长度
    	while(t[tlen]!='') tlen++; //计算t的长度
    	 
    	while(i<slen&&k<tlen) //任意字符串越界则结束循环
    	{
    		if(s[i]==t[k]) //相同则一起++
    		{
    			i++;
    			k++;
    		}
    		else            //不同则只有i++,但当前面相投后面不相同时,k=0,i退格+1.
    		{
    				k=0;
                                    i=i-k+1;	
    		}
    	}
    	if(k>=tlen)
    		return s+i-k; //返回地址
    	else
    		return NULL;	
    }
    

    他的代码思路清楚,文字注释较多,值得我去学习。
    2.2 题目名2(2分)

    这道题我没有做出来。
    2.3 题目名3(3分)

    #include<stdio.h>
    #include<string.h>
    int main()
    {
    	char c[600000];
    	gets(c);
    
    	int i,j,flag,l;	
    	l=strlen(c);
    	for(i=0;i<l;i++)
    		if(c[i]==' ')
    			c[i]='';
    	
    	for(;l>=0;l--)
    		if(c[l-1]==''&&c[l]!='')
    		{
    			flag=0;		
    			
    			for(i=l;c[i]!='';i++)
    				putchar(c[i]);
                for(j=0;j<l-1;j++)
    				if(c[j]!='')
                    {
    					flag=1;
    				break;
    				}
    			if(flag)
    			printf(" ")	;
    		}		
    }
    
  • 相关阅读:
    0X03异常错误处理
    (组合数学)AtCoder Grand Contest 019 F
    (NTT)AtCoder Grand Contest 019 E
    (dp)AtCoder Grand Contest 019 D
    (dp)AtCoder Regular Contest 081 E
    (最小费用流)hdu 6118(2017百度之星初赛B 1005) 度度熊的交易计划
    (容斥)Codeforces Round #428 (Div. 2) D. Winter is here
    (最大团)Codeforces Round #428 (Div. 2) E. Mother of Dragons
    (FFT)HDU 6088(2017 多校第5场 1004)Rikka with Rock-paper-scissors
    近期部分题目汇总
  • 原文地址:https://www.cnblogs.com/yang123789/p/14199191.html
Copyright © 2011-2022 走看看