zoukankan      html  css  js  c++  java
  • [C语言]进阶|指针与字符串

    ------------------------------------------------------------------------------------

    回顾:[C语言]指针与字符串

    指针的使用:

    /**
     * main.c by weiChen in 2015-5-4
     */
    #include <stdio.h>
    
    //定义函数体,使在main方法中能调用
    void swap(int *pa, int *pb);
    void minmax(int c[], int len, int *min, int *max);
    int divide(int d, int e, int *result);
    
    int main(void)
    {
        /*
         指针应用场景:
         1. 交换两个变量的值
    
         2. 函数返回多个值,某些值就只能通过指针返回;
            传入的参数实际上是需要保存带回的结果的变量(注:函数中指针的值将作为参数传入函数);
    
         3. 函数返回运算的状态,结果通过指针返回;
            常用的套路是让函数返回特殊的不属于有效范围内的值来表示出错;
                -1或0(在文件操作会看到大量的例子)
            但是当任何数值都是有效的可能结果时,就得分开返回了;
                   后续的语言(c++,java)采用了异常机制来解决这个问题
         4. 指针常见错误:定义了指针变量,还没有指向任何变量,就开始使用指针
         */
        int a = 5;
        int b = 6;
        swap(&a, &b);
        printf("a=%d,b=%d
    ", a, b);
    
        int c[] = {1,2,3,4,5,9,30,13,45,59};
        int min,max;
        minmax(c, sizeof(c)/sizeof(c[0]), &min, &max);
        printf("min=%d, max=%d
    ", min, max);
    
        int d = 19;
        int e = 3;
        int f;
        if(divide(d, e, &f)) {
            printf("%d/%d=%d
    ", d, e, f);
        }
        
        int i = 8;
        int *p;
        int k;
        k = 12;
        *p = 12;//未初始化变量,直接给指针赋值;一旦指针所指的位置不可写,程序将报错
        printf("&i=%p
    ", &i);//Segmentation fault
    
        return 0;
    }
    
    //交换两个值
    void swap(int *pa, int *pb)
    {
        int t = *pa;
        *pa = *pb;
        *pb = t;
    }
    
    //求最小最大值
    //虽然*min,*max是作为参数传进去的,但作用是得到结果,带入
    void minmax(int a[], int len, int *min, int *max)
    {
        int i;
        *min = *max = a[0];
        for(i=0; i<len; i++) {
            if(a[i] < *min) {
                *min = a[i];
            }
            if(a[i] > *max) {
                *max = a[i];
            }
        }
    }
    
    //@return 如果除法成功,返回1;否则返回0
    int divide(int d, int e, int *result)
    {
        int ret = 1;
        if(e == 0) {
            ret = 0;
        } else {
            *result = d/e;
        }
        return ret;
    }
    /**
     * main.c by weiChen in 2015-5-4
     */
    #include <stdio.sh>
    
    int main(void) 
    {
        /*
         指针与const
         指针可以是const: 0xaffefado
         值可以是const: 45
         */
    
        /*
         指针是const: 表示一旦得到了某个变量的地址,不能再指向其他变量
             int *const q = &i;    //q的值是const,值是i的指针
            *q = 26; //OK
            q++;    //ERROR
         */
         
        /*
         所指是const:表示不能通过这个指针去修改那个变量(并不能使得那个变量成为const)
             const int *p = &i;
            *p = 26;    //ERROR, (*p是const)
            i = 26;        //OK
            p = &j;        //OK
         */
    
        /*
         int i;
    
         const int *p1 = &i; 
                              |    指针不能被修改
         int const *p2 = &i; /
    
         int *const p3 = &i;
    
         //判断哪个被const了的标志是const在*的前面还是后面
         */
    
        /*
         转换:总是可以把一个非const的值转换成const的
         void f(const int *x);    //意思:传入一个const指针参数,但函数内部不会更改这个指针所指的值
         int a = 15;            //可以传入一个非const的指针的值
         f(&a);    //OK
    
         const int b = a;        //也可以传入一个非const的指针的值
         f(&b);    //OK
         b = a + 1; //ERROR
         
         //当要传递的参数的类型比地址大的时候,这是常用的手段:既能用比较少的字节数传递值给参数,又能避免函数对外面的变量的修改
         */
    
        /*
         const数组:
         const int a[] = {1,2,3,4,5,6,};
         数组变量已经是const的指针了,这里的const表明数组的每个单元都是const int (即a[0]等均为const)
         所以必须通过初始化进行赋值
         */
    
        /*
         保护数组值:
         因为把数组传入函数时传递的是地址,所以那个函数内部可以修改数组的值
         为了保护数组不被函数破坏,可以设置参数为const
             int sum(const int a[], int length);    //不希望函数对参数作修改
         */
    
        return 0;    
    }

    指针的计算: 

    /**
     * main.c 
     */
    #include <stdio.h>
    
    int main(void)
    {
        char ac[] = {0,1,2,3,4,5,6,};    //char数组
        char *p = ac;     //*p指向数组的第一个单元
        printf("p = %p
    ", p);            //p = 0x7fff51f1dc15
        printf("p + 1 = %p
    ", p + 1);    //p + 1 = 0x7fff51f1dc16
    
        int ai[] = {0,1,2,3,4,5,6,};   //int数组
        int *q = ai;    //*p指向数组的第一个单元
        printf("q = %p
    ", q);             //q = 0x7fff50160bf0
        printf("q + 1 = %p
    ", q + 1);     //q + 1 = 0x7fff50160bf4
    
        printf("sizeof(char)=%ld
    ", sizeof(char));    //1
        printf("sizeof(int)=%ld
    ", sizeof(int));    //4
    
        /*
         指针的计算:
             在指针上加1,是移到下一个单元,给实际的指针值加上sizeof类型的值
            两个指针相减,值是两个指针的差除以sizeof类型的值
         */
        
        //    *p -> ac[0]
        //    *(p+1) -> ac[1]
        //     *(p+n) -> ac[n]
        // 加1如果不加上sizeof(类型)的值,得到的其实并不是我们想要的
    
        // 给指针加1表示要让指针指向下一个变量:
        //    int a[10];
        //    int *p = a;
        //    *(p+1) -> a[1];
        // 如果指针不是指向一片连续分配的空间,如数组,则这种运算没有意义
    
        /*
         指针计算:
             给指针加减一个整数(+, +=, -, -=)
            递增递减(++/--)
            两个指针相减:值是有几个sizeof类型的值存在
         */
        while(*p!=-1) {
            printf("%d
    ", *p++);
        }
        /*
    
         *p++
            取出p所指的那个数据,顺便把p移到下一个位置去
            *的优先级虽然高,但是没有++高
            常用于数组类的连续空间操作
            在某些cpu指令上,这可以直接被翻译成一条汇编指令
         */
    
        /*
         指针比较:
             <, <=, ==, >, >=, != 都可以对指针做
             比较他们在内存中的地址
             数组中的单元的地址肯定是线性递增的
         */
        
        /*
         0地址:
            当然你的内存中有0地址,但是0地址通常是个不能随便碰的地址
            所以你的指针不应该具有0值
            因此可以用0地址来表示特殊的事情
                返回的指针是无效的
                指针没有被真正初始化(先初始化为0)
            NULL是一个预定义的符号,表示0地址,有些编译器不识别小些的null
                有的编译器不愿意你用0来表示0地址
         */
    
        /*
         指针的类型:
             无论指向什么类型,所有的指针的大小都是一样的,因为都是地址
            但是指向不同类型的指针是不能直接互相赋值的
            这是为了避免用错指针
         */
    
        /*
         指针的类型转换:
             void* 表示不知道指向什么东西的指针
                计算时与char* 相同(但不相通)
            指针也可以转换类型
                int *p = &i; void *q = (void*)p;//通过p看i是一个int,通过q看i是一个void(强制类型转换后赋给q)
            这并没有改变p所指的变量的类型,而是让后人用不同的眼光通过p看它所指的变量
                不再当你是int,而认为是void
         */
    
        /*
         用指针来做什么:
             需要传入较大的数据时用作参数
            传入数组后对数组做操作
            函数返回不止一个结果
                需要用函数来修改不止一个变量
            动态申请的内存
         */
        return 0;
    }

     动态内存分配:

    //  main.c
    //  Created by weichen on 15/6/10.
    //  Copyright (c) 2015年 weichen. All rights reserved.
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, const char * argv[]) {
        /*
         动态内存分配
         
         输入数据:输入数据时,先告诉你个数,然后再输入,要记录每个数据
         C99可以用变量做数组定义的大小,C99之前呢?int *a = (int*)malloc(n*sizeof(int));
        
         #include <stdlib.h>
         void* malloc(size_t size);
         1. 向malloc申请的空间的大小是以字节为单位的
         2. 返回的结果是void*,需要类型转换为自己需要的类型
         3. (int*)malloc(n*sizeof(int));
         */
        
        int number;
        int* a;
        int i;
        
        printf("输入数量:");
        scanf("%d", &number);
        // int a[number];   // C99写法
        a = (int*)malloc(number*sizeof(int));   //malloc返回的void*,所以需要类型转换一下,现在a就可以当做数组使用
        
        for (i=0; i<number; i++) {
            scanf("%d", &a[i]);
        }
        for (i=number; i>=0; i--) {
            printf("%d", a[i]);
        }
        
        free(a);    // 归还内存
        
        return 0;
    }
    /**
    * main.c
    */
    #include <stdio.h> #include <stdlib.h> int main(int argc, const char * argv[]) { // malloc:如果空间申请失败则返回0或者NULL void *p = 0; //free可以释放0或NULL,避免free的地址没有被分配时出错,习惯初始化指针为0 int cnt = 0; // 如果p的地址不是0(得到了地址),循环继续 while( (p = malloc(100*1024*1024)) ) { cnt++; } printf("分配了%d00MB的空间 ", cnt); free(p); /* p = malloc(100*1024*1024); p++; // pointer being freed was not allocated p = &i; // pointer being freed was not allocated free(p); */ /* 把申请得到的空间还给“系统” 申请过的空间,最终都应该要还 只能还申请来的空间的首地址 常见问题: 申请了没有free,长时间运行内存逐渐下降:忘了或找不到合适的free的时机 free过了再free 地址变过了,直接取free */ return 0; }

    字符串操作:

    /**
     *  main.c
     */
    
    #include <stdio.h>
    
    int main(int argc, const char * argv[]) {
        /*
         单字符输入输出: putchar,getchar
         
         int putchar(int c);
         向标准输出写一个字符
         返回写了几个字符,EOF (-1)表示写失败(end of file)
         
         int getchar(void);
         从标准输入读入一个字符
         返回类型是int是为了返回EOF (-1):Windows->Ctrl-Z
                                       Unix->Ctrl-D
         */
        
        int ch;
        
        while( (ch = getchar()) != EOF ) {
            putchar(ch);
        }
        
        return 0;
        
        /*
         字符串数组:
         char **a;
            a是一个指针,指向另一个指针,那个指针指向一个字符(串)
         char a[][1];
         
         */
    }

    字符串函数实现:

    //  main.c
    //  Created by weichen on 15/6/23.
    //  Copyright (c) 2015年 weichen. All rights reserved.
    
    #include <stdio.h>
    #include <string.h>
    //自定义求长度的函数 int mylen(const char *s) { int index = 0; //知道长度用for循环, 不知道用while while (s[index] != '') { index++; } return index; } int main(int argc, const char * argv[]) {
       /**
       * size_t strlen(const char *s);
    * 返回s的字符串长度(不包括结尾的0)
       */
    char line[] = "hello";
       printf(
    "strlen=%d ", strlen(line)); //strlen=5 printf("strlen=%d ", mylen(line)); printf("sizeof=%d", sizeof(line)); //sizeof=6 return 0; }
    //  main.c
    //  Created by weichen on 15/6/23.
    //  Copyright (c) 2015年 weichen. All rights reserved.
    #include <stdio.h> #include <string.h> int mycmp(const char *s1, const char *s2) { //当做数组处理:用一个整数当做下标,遍历字符串 /* int index = 0; while (1) { if(s1[index] != s2[index]) { break; } else if(s1[index] == '') { break; } index++; } return s1[index] - s2[index]; */ //直接用指针:指针加加,判断指针所指的值 while (1) { if(*s1 != *s2) { break; } else if(*s1 == '') { break; } s1++; s2++; } return *s1 - *s2; //好看的写法 /* while (*s1 == *s2 && *s1 != '') { s1++; s2++; } return *s1 - *s2; */ } int main(int argc, const char * argv[]) { /** * strcmp * int strcmp(const char *s1, const char *s2); * 比较两个字符串,返回: * 0 :s1==s2 * 1 :s1 >s2 * -1:s1 <s2 */ char s1[] = "abc"; char s2[] = "abc "; printf("%d ", strcmp(s1, s2)); //0 printf("%d ", mycmp(s1, s2)); //判断两个字符串是否相等的写法 if(strcmp(s1, s2) == 0) { printf("s1 = s2"); } else { printf("s1 != s2"); } return 0; }
    //  main.c
    //  Created by weichen on 15/6/23.
    //  Copyright (c) 2015年 weichen. All rights reserved.
    
    #include <stdio.h>
    #include <string.h> char* mycmp(char *dst, const char *src) { /* 数组方式 int index = 0; while(src[index] != '') { dst[index] = src[index]; index++; } //src所有的字符串复制完后,dst还差一个结尾的0,需要加上去 dst[index] = ''; return dst; */ //指针方式 char* ret = dst; while (*src != '') { *dst = *src; src++; dst++; } *dst = ''; return ret; } int main(int argc, const char * argv[]) { /** * strcpy * char * strcpy(char *restrict dst, const char *restrict src); * 把src的字符串拷贝到dst,restrict表明src和dst不重叠(C99) * 返回dst,为了能链起代码来 */ /* 复制一个字符串的套路 char *dst = (char*)malloc(strlen(src) + 1); //不知道要复制的字符串占多大空间,所以需要动态分配内存,strlen只能求出字符串的大小,不包含结尾的0 strcpy(dst, src); */
      
       char s1[] = "abc";
       char *str = (char*)malloc(strlen(s1) + 1);
    strcpy(str, s1);
       printf("%s", str); return 0; }
    //  main.c
    //  Created by weichen on 15/6/26.
    //  Copyright (c) 2015年 weichen. All rights reserved.
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    int main(int argc, const char * argv[]) {
        /*
         在字符串中找单个字符
         char* strchr(const char *s, int c);
         char* strrchr(const char *s, int c);
         返回NULL表示没有找到
         */
        
        char s[] = "hello";
        char *p = strchr(s, 'l');
        printf("%s
    ", p);  //llo
        
        //找第二个l
        char *q = strchr(p + 1, 'l');
        printf("%s
    ", q);  //lo
        
        //从右边开始找
        char *a = strrchr(s, 'l');
        printf("%s
    ", a);  //lo
        
        //复制找到的字符串
        char *r = (char*)malloc(strlen(p) + 1); //1.动态分配内存空间
        char *t = strcpy(r, p);                 //2.复制字符串
        printf("%s
    ", t);  //llo
        free(r);                                //3.释放动态分配的内存空间
        
        //找l之前字符的技巧
        char c = *p;
        *p = '';          //将*p所指的位置替换为; s就变成了helo
        char *u = (char*)malloc(strlen(s) + 1);
        char *v = strcpy(u, s);
        printf("%s
    ", v);  //he
        printf("%s
    ", s);  //he
        free(u);
        
        //最后将*p恢复为l
        *p = c;
        printf("%s
    ", s);  //hello
        
        
        /*
         字符串中找字符串
         char* strstr(const char *s1, const char *s2);
         字符串中找字符串,并忽略大小写
         char* strcasestr(const char *s1, const char *s2);
         */
        char x[] = "E";
        char y[] = "e";
        char *z1 = strstr(s, x);    //如果第二个参数x改为字符'E',就会报错,因为函数接受的参数是一个指针;
        char *z2 = strstr(s, y);
        char *z3 = strcasestr(s, x);
        printf("%s
    ", z1); //null
        printf("%s
    ", z2); //ello
        printf("%s
    ", z3); //ello
        
        /*
         连接两个字符串
         extern char* strcat(char *dest, char *src);
         */
        char ab[10] = "good";
        char *cd = "bye";
        strcat(ab, cd);
        printf("%s
    ", ab); //goodbye
        
        return 0;
    }
    
    //注:PHP中strchr是strstr的别名,因为里面没有指针一说,所以第一第二个参数均为字符串。

    Link:http://www.cnblogs.com/farwish/p/4477897.html

  • 相关阅读:
    如何入门深度学习
    机器学习之激活函数
    轻量化模型之SqueezeNet
    聚类算法之MeanShift
    目标检测之RefineDet
    语义分割之RefineNet
    数学基础之高斯核函数
    目标检测之人脸识别
    梯度下降算法及优化方法
    机器学习高阶训练营知识点一览
  • 原文地址:https://www.cnblogs.com/farwish/p/4477897.html
Copyright © 2011-2022 走看看