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(" ")	;
    		}		
    }
    
  • 相关阅读:
    JZOJ 3034. 【NOIP2012模拟10.17】独立集
    JZOJ 3035. 【NOIP2012模拟10.17】铁轨
    JZOJ 1259. 牛棚安排
    数位DP JZOJ 3316. 非回文数字
    JZOJ 3046. 游戏
    JZOJ 3013. 填充棋盘
    debian 安装oracle提供的java8
    java 汉字转拼音 PinYin4j
    debian ssh设置root权限登陆 Permission denied, please try again
    java并发下订单生成策略
  • 原文地址:https://www.cnblogs.com/yang123789/p/14199191.html
Copyright © 2011-2022 走看看