str函数和指针的理解

1.strlen 用来计算一个指定的字符串的长度
    
NAME
       strlen - calculate the length of a string
        计算一个指定的字符串的长度
SYNOPSIS
       #include <string.h>

       size_t strlen(const char *s); //函数原型
        s:字符指针,指向你要计算长度的字符串的首地址
        返回值:
            返回s指向的字符串的长度
DESCRIPTION
       The  strlen()  function calculates the length of the string pointed to by s, excluding(排除/不包括) the terminating null byte ('\0').

RETURN VALUE
       The strlen() function returns the number of characters in the string pointed to by s.    

    例子:
        char s[] = {"1234567"};
        sizeof(s) == 8
        
        l = strlen(s+3);
        l = ? 4
        
        char s1[4] = {'A','B'};
        l = strlen(s1);
        l = ? 2
        
        char s2[4] = {'A','B','C','D'};
        l = strlen(s2);
        l = ? 不确定


    2.strcpy/strncpy  复制一个字符串(string copy)

NAME
       strcpy, strncpy - copy a string
        
SYNOPSIS
       #include <string.h>
        字符串拷贝函数,把一个字符串拷贝到另一个字符串中去
        strcpy用来把src指向的字符串,拷贝到dest指向的内存空间中去
        一个字符一个字符的拷贝,直到遇到第一个'\0'(如果不遇到'\0',就一直copy)
        '\0'也会被复制
       char *strcpy(char *dest, const char *src);
        dest:指向目的地地址
        src:指向要复制的字符串的首地址
        const char *src:保证不会通过src这个指针去修改src指向的内容
                        增强程序的健壮性
        返回值:
            返回一个指针类型(地址编号)
            返回拷贝后的dest的首地址
            
        例子:
            char s[6]; //sizeof(s) == 6,strlen(s) == 不确定
            char *p;
            
            p = strcpy(s,"123456"); //返回dest的地址,dest的就是s的地址,p就指向了s
            printf("s = %s\n",s);
            printf("p = %s\n",p);
            ====================================================
            char s[10] = {"ABCDEFGHIJ"}; 
            char *p;
            
            p = strcpy(s,"123456"); //返回dest的地址,dest的就是s的地址,p就指向了s
            printf("s = %s\n",s);
            printf("p = %s\n",p);
            ====================================================
            char *q; //野指针,q指向的内存区域不一定可用
            //strcpy(q,"123");  //很有可能会有段错误,q指向的内存区域不一定可用
                            //q指向的地方没有一块可以的空间.
            //printf("%s\n",q);
            
            ====================================================
            char s1[8];
            char s2[8] = {"abcdefg"};
            //一般的编译器会把s1和s2放到连续的空间
            printf("s1 = %p\n",s1);
            printf("s2 = %p\n",s2);
            
            strcpy(s1,"1234567890");
            printf("s1 = %s\n",s1);//s1 = 1234567890

            printf("s2 = %s\n",s2);//s2 = 90    
            
        从上面的结果可以看出,strcpy的设计者在设计strcpy的时,可能喝了一点假酒,写了一个有bug的程序,strcpy可能会破坏dest后面的内存,为了修改这个错误,设计了一个strncpy
            
      
        strncpy的功能和strcpy类型,只不过它最多拷贝src前面的n(一般会指定dest的最大可用空间)个字符,那么strncpy到底会copy多少个字符呢?
            1.遇到了\0会结束copy,'\0'也会被复制
            2.已经拷贝了n个字符,strncpy也会结束(\0不会被自动copy,除非\0是第n个字符)
                不管什么情况,最多是n个字符
        char s[10];
        strncpy(s,"0123456789abcdefg",10);
        
         char *strncpy(char *dest, const char *src, size_t n);
            dest:指向目的地地址
            src:指向要复制的字符串的首地址
            n:最多copyn个字符(一般会指定dest的最大可用空间)
            返回值:
                返回一个指针类型(地址编号)
                返回拷贝后的dest的首地址
                
    3.strcmp/strncmp 比较两个字符串是否相等
    NAME
        strcmp, strncmp - compare two strings
        比较两个字符串
    SYNOPSIS
           #include <string.h>
            
           int strcmp(const char *s1, const char *s2);
            s1:要比较的第一个字符串的地址
            s2:要比较的第二个字符串的地址
            字符串是如何比较的?
            逐个字符依次比较(比较每一个字符的ASCII码)
            一个字符一个字符的比较
            返回值:
                The strcmp() and strncmp() functions return an integer less than(小于), equal to(等于), or greater than(大于) zero 
                if s1(or  the  first n bytes thereof) is found, respectively, to be less than, to match, or be greater than s2.
                如果发现s1(或其前n个字节)分别小于(返回<0),等于(返回==0)或大于s2(返回>0)。
            
            if(c1 > c2)  //返回 >0
            {            
                    不同的标准实现方式不一样,
                    有的是返回1
                    有的返回ASCII码的差值
            }
            
            if(c1 < c2) 返回 <0 
                        有可能是-1
                        
            if(c1 == c2) 继续比较下一个字符,直到都同时遇到\0,返回0            
            
            strcmp("123","ABC"); -----> <0
            strcmp("123","12A"); -----> <0
            strcmp("123","123\0ABC");  -----> ==0
            strcmp("1234","123"); ----> >0
            
            char s1[10] = {...}
            char s2[10] = {...}
            strcmp(s1,s2); //按照上面的规则对照即可
            
            strncmp和strcmp类似,用来比较s1和s2前面的n个字符是否相等
           int strncmp(const char *s1, const char *s2, size_t n);
            strncmp(s1,"ABC",3);
            //验证s1前面三个字符是否为ABC

    4.strcat/strncat 字符串连接函数
    
    NAME
           strcat, strncat - concatenate two strings
            连接两个字符串
    SYNOPSIS
           #include <string.h>
            strcat用来把src指向的字符串拷贝(连接)到dest指向的字符串的末尾(连接到末尾)
           char *strcat(char *dest, const char *src);
                dest:目标字符串,指向一段可用的空间
                    空间应该足够大,至少能放得下src指向的字符串
                src:被拷贝的字符串
                返回值:
                    如果成功,返回连接后的字符串的首地址(dest)
                    如果失败,返回NULL(空指针,在C语言中的即编号为0的地址)
                    //访问(读/写)空指针都会造成段错误
            

            例子:
                char s1[12] = {"ABCDEFG"};
                strcat(s1,"12345");
                先去掉dest后面的\0
                在把src指向的字符串复制过去
                s1:ABCDEFG12345
                
            上面的函数可能会造成内存越界,strncat是用来修复strcat的那一个bug的
                    
           char *strncat(char *dest, const char *src, size_t n);
            strncat把src指向的字符串拷贝到dest的末尾,但是它最多拷贝n个字符,
            strncat到底会copy多少个字符呢?
                1.遇到了\0会结束copy,'\0'也会被复制
                2.已经拷贝了n个字符,strncat也会结束(\0不会被自动copy,除非\0是第n个字符)
                    不管什么情况,最多是n个字符
    
12.函数与指针
    在C语言中,函数也是有地址的,既然函数有地址,是不是可以定义一个变量去保存函数的地址呢?
        肯定可以,
        指针变量,保存函数的地址(指向函数的指针--函数指针)
        
    1.函数指针如何定义
        指向的对象的类型 *指针变量名;
        int sum(int a,int b)
        {
            printf("i am sum\n");
            return a+b;
        }
        expected ‘char *’ but argument is of type ‘int (*)(int,  int)’
        &sum的类型是 int (*)(int,  int)
        假设我要定义一个指针变量p,保存sum函数的地址,怎么定义?
            指向的对象的类型 *p;
                要保存sum的地址,指向的类型就是sum的类型
                typeof(sum) *p;
                typeof(sum):如何描述一个函数的类型呢?
                    函数的三要素:
                    返回值类型 函数名(函数的参数类型列表);
                    int sum(int a,int b); 
                    //sum是int (int,int)类型的函数(把名字去掉就是对象的类型)
                    //有一个int的返回值,有两个int类型的参数的函数
                                        
                typeof(sum) ====>int (int,int);
                ======>
                int (int,int) *p; //C语言中括号不能和关键字写在以前
                ======>    
                int *p(int,int); //编译器会把这个东西认为是函数的声明
                                //声明了一个函数p,有一个int *的返回值,有两个int类型的参数
                                 //指针函数:返回值为指针的函数
                    括号的优先级比*高,所有正确的定义方法:
                ======>    
                int (*p)(int,int);    //函数指针类型,
                            //把名字去掉就是对象的类型,p的类型是int (*)(int,int)    
                            
                (*p)说明p是一个指针类型,可以保存一个int (int,int)类型的函数的地址。
                
        每一个函数都是有类型的,如果类型不匹配,就会报错:
            void f(int a,double b);
            typeof(f) --->void (int,double)
            
            void f(void);
            typeof(f) --->void (void)
            
            void *f(int *p);
            typeof(f) --->void *(int *)
            如果需要定义一个函数指针p,指向上面的函数(保存上面的函数的地址)。
            void *(int *) *p;
            ---->
            void *(*p)(int *);

        总结,函数指针的定义方法:
            指向的函数的返回值类型 (*指针变量名)(函数的参数类型列表);
            
        例子:
            void swap(int *pa,int *pb);
            要定义一指针变量p,来保存swap的地址
            
            void (*p)(int *,int *);
            //p就可以保存一个返回值为void有两个int*参数的函数的地址
            p还没有赋值(p是一个野指针),不确定指向的指针就是野指针
    2.函数指针如何赋值
        p = 函数的地址;
        函数的地址如何获取呢?
            &函数名
            or
            函数名
            在C语言中,函数名就代表函数的首地址(入口地址)
            
            =====》
            p = &sum;
            or
            p = sum;
            (只有当sum为函数时,sum和&sum才一样)
            
        函数指针已经保存了函数的地址,能不能通过p去调用这个函数呢?
            肯定可以
            
    3.如何通过函数指针去调用函数呢?
        在前面已经让p指向了函数(保存了函数的地址)
        取地址对应的对象使用 *
        p(3,5);  //只有当p是函数指针才可以这样
        or
        (*p)(3,5);
        
        *p(3,5); //ERROR    
            
            
        只有当p是函数指针时,
            *p <-----> p
            
        如果指向的函数没有参数呢?
        p();
        or
        (*p)();
        
        通过函数指针调用函数有两种方式:
            1.(*函数指针变量名)(实参列表);
            2.函数指针变量名(实参列表);

    4.函数指针在C语言中的意义
        实现C语言的回调函数。
        在调用同一个函数的时候,根据函数的走向可以决定是否调用另一个函数
        
        本质:
            就是把函数A的地址当做参数传递到拎一个函数B中去,另一个函数可以通过传递进来的地址去调用函数A,
            函数的地址当做函数的参数。

        例子:
        


13.二级指针和多级指针
    
    int a; //定义了一个变量a,分配了4字节空间
    可以定义一个指针变量p,来保存a的地址
    typeof(a) *p; //指向的类型 * 指针变量名;
    int *p;
    p = &a; //p保存了a的地址,指向了a
    
    p也是一个变量,OS也为它分配了空间,分配了8字节空间,空间里面存储的是a的地址
    p的8字节空间,是不是本身也有地址,我们可不可以定义一个指针变量p2来保存p的地址呢?
        肯定可以.
        如果可以,p2应该是什么类型呢?
        p的地址为&p,把&p赋值给p2
        p2 = &p;
        赋值符号两边的类型应该一致
        &p的类型就是p2的类型
        &p:肯定是一个地址,保存了p的地址,指向了p
        &p---->typeof(p) *----->int **;
    
        typeof(p) *p2; //p的类型是int*
        ====>
        int **p2;
            //p2就是我们所说的二级指针,它保存了一个一级指针的地址
        p2 = &p; //p2保存了p的地址
        p2 = &a; //ERROR
            p2:int**
            &a:int *
            
        sizeof(p2) == 8;  //所有的指针都是8字节

        可以通过p2去访问a吗?
            肯定可以(知道一个地址就可以访问内存)
            如何访问?
            
            *p2 ----> *&p ---->p ----->&a
            *p -----> *&a ---->a
            
            **p2---->**&p----->*p
            
            **p2 = 1025; //a = 1025;
            
    p2也是一个变量,也有自己的内存空间和编号,是不是可以定义一个变量p3去保存p2的地址呢?
        肯定可以
        p3 = &p2;
        p3是什么类型呢?
        typeof(p2) *
        =====>
        int ***p3; //三级指针
        
    p3也是一个变量.......

    二级指针和多级指针比较绕,分不清的话,不要管它是几级指针,只要知道它是一个指针就可以了
    并且知道保存了谁的地址

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值