七、指针:字符串处理函数:strlen、strcpy、strncpy、strcat、strncat、strcmp、strncmp、sprintf、sscanf、strchr、strstr、strtok、atoi、atof、atol

指针基础知识

 

复制代码
指针和指针变量;指针变量的定义与使用;指针的大小;
==========================================================================================================
指针和指针变量
    内存区的每一个字节都有一个编号,这就是“地址”。
    如果在程序中定义了一个变量,在对程序进行编译或运行时,系统就会给这个变量分配内存单元,并确定它的内存地址(编号)
    指针的实质就是内存“地址”。指针就是地址,地址就是指针。
    指针是内存单元的编号,指针变量是存放地址的变量。
    通常我们叙述时会把指针变量简称为指针,实际他们含义并不一样。
        口语上的指针实际上是指针变量


----------------------------------------------------------------------------------------------------------
//指针变量的定义与使用;指针的大小
int main()
{
    //    指针也是一种数据类型,指针变量也是一种变量
    //指针变量指向谁,就把谁的地址赋值给指针变量
    //“*”操作符操作的是指针变量指向的内存空间
    
    //我的理解:指针是特殊的变量
    // 普通的变量储存的是内容;而指针储存的是地址
    // 指针如果是在左边,那么就是用来进行指针指向地址的内容修改,即修改对应的普通变量的内容
    // 指针如果是在右边,那么就是用来取值,取出指针指向地址的内容,即取出普通变量的内容
    // 
    
    //int * p //这里的*表示类型描述符,这里是一个指针
    //*p : 将p变量的内容取出,当成地址看待,找到该地址对应的内存空间。
    // 
        //*p 如果做左值: 存数据到空间中。---存数据
        //*p 如果做右值: 取出空间中的内容。---取数据
    int a = 10;
    int* p = &a;
    
    //*p = 2000;
    a = 2000; //效果等同于 "*p = 2000;"
    printf("%d\n", a);    //2000                变量a的内容
    printf("%p\n", &a);    //000000F7E12FF784    变量a的内存地址
    printf("%p\n", p);    //000000F7E12FF784    变量a的内存地址,很好理解,因为指针的内容就是普通变量的地址嘛
    printf("%p\n", &p);    //000000D2A1CFF818    变量p的内存地址,这个是指针变量的地址,当然与普通变量的地址是不同的
    printf("%p\n", *p);    //00000000000007D0    7D0十六进制,即2000,此处做右值,去除空间的内容
    printf("%d\n", *p);    //2000                7D0十六进制,即2000,此处做右值,去除空间的内容
    
    //指针的大小与数据类型无关,只与平台的架构有关;32位系统即4字节;64位系统即8字节
    //很正常,可以理解,指针就是一种特殊的变量嘛,存的是地址,自然不需要不同的大小
    printf("%u\n", sizeof(int *));    //打印出来全是8;
    printf("%u\n", sizeof(short *));
    printf("%u\n", sizeof(char *));
    printf("%u\n", sizeof(long *));
    printf("%u\n", sizeof(double *));
    printf("%u\n", sizeof(void *));
    
    // *p   就是指针的解引用、间接引用;我的理解就是根据纯粹的地址数据找到了地址空间
}
指针和指针变量;指针变量的定义与使用;指针的大小;
复制代码

 

复制代码
野指针;空指针;万能指针(泛型指针)
==========================================================================================================
指针变量也是变量,是变量就可以任意赋值,不要越界即可(32位为4字节,64位为8字节),但是,任意数值赋值给指针变量没有意义,
因为这样的指针就成了野指针,此指针指向的区域是未知(操作系统不允许操作此指针指向的内存区域)。
所以,野指针不会直接引发错误,操作野指针指向的内存区域才会出问题。
//【野指针一定要杜绝】
//【空指针要进行强制类型转换后,才能使用】
int main()
{
    //野指针
    int* p1;        //野指针1
    //野指针是肯定需要避免的,因为定义了野指针,却不指定指针的内容,那么意味着指针内容可能是随机数。
    //假设这个随机地址指定到了另一个数据的空间,那不就修改了其他数据了。。这种情况肯定是不能被允许的!
    *p1 = 2000;
    printf("%d\n",*p1);

    int* p2 = 10;    //野指针2    
    //因为0-255这个地址段是要留给操作系统使用的,此处给的地址10是非法地址
    //所以直接给指针赋值,这种方式也是非法的;你怎么知道你不会指到关键数据上呢。。
    //我的猜测:指到关键数据碰到的问题不一定就是修改了关键数据;也可能是非法访问,不被允许,总之就是有问题。。
    *p2 = 2000;
    printf("%d\n", *p1);

    //正确的使用方式
    int m;
    int* p3;
    p3 = &m;
    //int* p3 = &m;

    //空指针
    int* p4 = NULL;        //#define NULL ((void *)0);  是一个指向0地址的万能指针
    //...一系列操作之后
    if (p4 != NULL) {    //确定指针地址是有效的,再执行操作
        *p4 = 300;
        printf("%d", *p4);
    }
}

----------------------------------------------------------------------------------------------------------
万能指针(泛型指针)
int main()
{
    //万能指针(泛型指针)
    void* p;
    int a = 123;
    p = &a;
    //使用万能指针前,需要先强制转换指针类型
    printf("%d\n",*((int *)p));    //显示正常,打印123
    //printf("%d\n",*p);        //错误用法,不允许使用不完整的类型

    //普通变量的强制转换 (int)aaa
    //指针的强制转换    (int *)aaa
}
野指针;空指针;万能指针(泛型指针)
复制代码

 

复制代码
const修饰的指针变量;
==========================================================================================================
const修饰的指针变量
int main()
{
    //const 修饰变量
    const int a = 100;
    printf("%d\n", a);    //100
    //a = 200;            //只读变量,不能修改
    int* p = &a;
    *p = 200;
    printf("%d %d\n", a,*p);    //200 200;只读变量虽然不能直接修改,但是可以通过指针来间接修改

    //const 修饰指针
    const int* p1;
    int const* p2;
    int* const p3;
    const int* const p4;
    int aa = 50;
    p1 = &aa;    //这种方式可以修改;"*p1 = 500;"这种方式不能修改
    p2 = &aa;    //同上, "*p1 = 500;"会报错
    *p3 = 500;    //这里的现象不同了,"p3 = &aa;"这种形式会报错;
    //p4,两种方式都不能修改。

    //结论:const向右进行修饰,被修饰则无法修改,变成只读
    //p1p2锁的是指针指向的内存空间,即造成指向的变量不能修改,即 *p 无法修改;
    //p3锁的是指针变量的内容,但是指向的内存空间,即指向的变量并没有被锁定,可以修改。
    //p是指针变量本身,储存的只是内存地址这种数据;*p则是指相应的内存空间,相当于是变量了。。

    //int fputs(const char * str, FILE * stream);
    //以上为常用方式,const用在函数形参中,限制指针所指向的内存空间变为只读。
    //此处添加了const是为了函数的健壮性:
    
    
}

------------------------------------------------------------------------------
int main()
{
    // const 测试
    int a1 = 1;
    int a2 = 2;
    int a3 = 3;
    
    const int* p1 = &a1;
    int const* p2 = &a2;
    int* const p3 = &a3;

    printf("%d\n", a1);            //打印1
    printf("%d\n", *p1);        //打印1
    a1 = 100;
    printf("%d\n", a1);            //打印100
    printf("%d\n", *p1);        //打印100
    //*p1 = 1000;    指针变量的解引用被锁,无法修改
    p1 = &a2;
    printf("%d\n", a1);            //打印100
    printf("%d\n", *p1);        //打印2        指针变量内容被修改为a2的地址,解引用后取出a2的数据
    printf("++++++++++++++++++++++++++++++++++++++++\n");
    printf("%d\n", a3);            //打印3
    printf("%d\n", *p3);        //打印3
    //p3 = &a1;        指针变量内容被锁,无法修改
    *p3 = 300;    
    printf("%d\n", a3);            //打印300
    printf("%d\n", *p3);        //打印300
    a3 = 3000;
    printf("%d\n", a3);            //打印3000
    printf("%d\n", *p3);        //打印3000
}
const修饰的指针变量;
复制代码

 

指针和数组、多级指针 

 

复制代码
指针与数组;指针操作数组元素
----------------------------------------------------------------------------------------------------------
指针与数组;指针操作数组元素
int main()
{    //指针与数组;指针操作数组元素

    //数组名是地址【常量】        那不就是相当于 * const p 么。。。 
    int arr[] = { 1,2,3,4,5 };
    printf("%d\n", arr[2]);          //打印3
    printf("%d\n", sizeof(arr[2]));  //4字节
    printf("%p\n", arr);        //打印00000067D5CFF638
    printf("%p\n", arr + 1);    //打印00000067D5CFF63C    //这个地方+1,并不是地址+1,而是+1地址段。。
    printf("%p\n", arr + 2);    //打印00000067D5CFF640
    printf("%d\n", *(arr + 2));   //打印3                    //这种方式也能完成取地址,【重点理解!!!!】
    printf("=========================================================\n");
    double arr2[] = { 1,2,3,4,5 };
    printf("%lf\n", arr2[2]);        //打印3.000000
    printf("%d\n", sizeof(arr2[2]));  //8字节
    printf("%p\n", arr2);            //打印00000067D5CFF668
    printf("%p\n", arr2 + 1);        //打印00000067D5CFF670
    printf("%p\n", arr2 + 2);        //打印00000067D5CFF678    
    printf("%f\n", *(arr2 + 2));    //打印3.000000

    printf("=========================================================\n");
    int arr3[] = { 1,2,3,4,5 };
    int* p3 = arr3;
    printf("%d\n", arr3[3]);        //打印4,获取数组元素的方式1
    printf("%d\n", *(arr3 + 3));    //打印4,获取数组元素的方式2
    printf("%d\n", p3[3]);            //打印4,获取数组元素的方式3
    printf("%d\n", *(p3 + 3));        //打印4,获取数组元素的方式4
    // arr3[3] == *(arr3+3) == p3[3] == *(p3 + 3) 看起来指针和数组很相似。。。

    //指针与数组名的区别
    //1.指针是变量;数组名是常量
    //2.sizeof(指针)= 4/8(取决于平台);sizeof(数组名)= 数组的长度

    //数组名是地址常量,对数组名进行取地址'&'操作,得到的地址仍是这个地址常量
    //指针是保存地址的变量,对指针变量进行取地址'&'操作,得到的是指针变量所在内存空间的地址
}
指针与数组;指针操作数组元素
复制代码

 

复制代码
指针加减运算;数组地址的加减;指针加减指针
==========================================================================================================
指针加减运算
加法运算
    指针计算不是简单的整数相加
    如果是一个int *,+1的结果是增加一个int的大小
    如果是一个char *,+1的结果是增加一个char大小


int main()
{
    //指针变量的加减
    int a = 0x12345678;
    int* p1 = &a;
    char* p2 = &a;
    printf("%p\n", *p1);        //0000000012345678
    printf("%p\n", *p2);        //0000000000000078        猜到了只会读取1字节,但是没猜到是从低地址位开始读。。
                                                //所以在内存中的实际存储可能并不是想象的0000000010101010,可能实际是倒序存储的???
    //指针类型影响了读取数据的长度

    printf("%p\n", p1);        //0000005C3A72F934
    printf("%p\n", p1 + 1);    //0000005C3A72F938        //指针变量内容的+1,并不是直接+1,而是+1个指针类型长度的字节数
    printf("%p\n", p2);        //0000005C3A72F934
    printf("%p\n", p2 + 1);    //0000005C3A72F935    

    //我的理解:
    //指针变量的加减逻辑和普通变量的加减逻辑是不一样的!
    //指针变量的加减关乎于指针类型以及加减值
    //普通变量的加减,只在于数据本身
    printf("=========================================================\n");
    //使用指针获取数组元素
    int arr[] = { 1,2,3,4,5,6,7,8,9 };
    int* p3 = arr;
    for (size_t i = 0; i < 9; i++)
    {                
        printf("%d ", *p3);    //打印:1 2 3 4 5 6 7 8 9
        p3++;
    }
    printf("数组的元素数量:%d\n",(p3-arr));        //数组的元素数量:9   (指针变量的加减还是得取决于变量类型!!!)
    printf("数组的元素数量:%d\n", (&arr[8] - &arr[0] + 1));    //数组的元素数量:9
    
    //指针变量是不能进行乘除的
}

-----------------------------------------------------------------------------------------------------
int main()
{
    //数组地址的加减
    int a[] = { 1,2,3,4,5,6,7,8,9, };
    printf("%p\n", a);        //000000791B12F5D8
    printf("%p\n", a + 1);    //000000791B12F5DC    移动4字节
    printf("%p\n", &a);        //000000791B12F5D8
    printf("%p\n", &a + 1);    //000000791B12F5FC    移动36字节,因为数组中有9个元素;若改变数组中的元素个数,那么&a + 1移动的字节数也会发生变化
}


-----------------------------------------------------------------------------------------------------
int main()
{
    //指针加减指针
    int a = 10,b = 20;
    int* p1 = &a, * p2 = &b;
    p1 - p2;    //指针指针相减
    //p1 + p2;  不支持指针相加
    printf("%p\n", p1);        //00000027DB2FF744
    printf("%p\n", p2);        //00000027DB2FF764
    printf("%d\n", p1 - p2);    //-8,相差8个单位(元素),即32字节
    printf("%p\n", p1 - p2);    //FFFFFFFFFFFFFFF8,相差8个单位(元素),即32字节
    printf("%p\n", p2 - p1);    //0000000000000008,相差8个单位(元素),即32字节

    if (p1 < p2)                //指针地址是可以相比较的
        printf("p2指向的地址靠后");
    else
        printf("p1指向的地址靠后");
}
指针加减运算;数组地址的加减;指针加减指针
复制代码

 

复制代码
指针数组;多级指针
==============================================================================================
指针数组,它是数组,数组的每个元素都是指针类型。
int main()
{
    //指针数组
    int a = 1, b = 2, c = 3, d = 4, e = 5;
    int* arr[] = { &a, &b, &c, &d, &e, };
    printf("%d\n", *arr[0]);    //打印:1
    printf("%d\n", *arr[1]);    //打印:2
    printf("%d\n", *arr[2]);    //打印:3
    printf("%d\n", **arr);            //打印:1    数组名解引用后,获取到储存的地址;对该地址解引用,则获取到数据内容
    printf("%d\n", *(*(arr)));        //打印:1    数组名解引用后,获取到储存的地址;对该地址解引用,则获取到数据内容
    printf("%d\n", *(*(arr+0)));    //打印:1    数组名解引用后,获取到储存的地址;对该地址解引用,则获取到数据内容
    printf("%d\n", *(*(arr+1)));    //打印:2    数组名解引用后,获取到储存的地址;对该地址解引用,则获取到数据内容
    printf("%d\n", *(*(arr+1)));    //打印:3    数组名解引用后,获取到储存的地址;对该地址解引用,则获取到数据内容
    //双*  就是二级指针

    printf("%p\n", arr[0]);    //打印:000000C5909DF464
    printf("%p\n", arr[1]);    //打印:000000C5909DF484
    printf("%p\n", arr[2]);    //打印:000000C5909DF4A4

    int aaa = arr[0];
    //printf("%d\n", *aaa);    //不能这么操作,提示 *后面跟的必须是指针
}

------------------------------------------------------------------------------------------------
多级指针 
    C语言允许有多级指针存在,在实际的程序中一级指针最常用,其次是二级指针。
    二级指针就是指向一个一级指针变量地址的指针。
    三级指针基本用不着,但考试会考。


int main()
{
    //多级指针
    //多级指针不能跳跃定义,比如在没有一级指针的前提下,不能直接定义二级指针
    int a = 100;
    int* p = &a;
    int** pp = &p;
    int*** ppp = &pp;
    int**** pppp = &ppp;
    printf("%d\n",a);            //打印输出都是100
    printf("%d\n",*p);
    printf("%d\n",**pp);
    printf("%d\n",***ppp);
    printf("%d\n",****pppp);

    printf("%p\n",***pppp);        //00000099C299F914
    printf("%p\n",&a);            //00000099C299F914
}
指针数组;多级指针
复制代码

 

指针和函数

 

复制代码
指针和函数;传数值和传地址;函数形参改变实参的值
=================================================================================
指针和函数:
    栈 帧:
        当函数调用时,系统会在 stack 空间上申请一块内存区域,用来供函数调用,主要存放 形参 和 局部变量(定义在函数内部)。
        当函数调用结束,这块内存区域自动被释放(消失)。
-------------------------------------------------------------------------------------------------
    传值和传址:
        传数值:函数调用期间,实参将自己的值,拷贝一份给形参。 
        传地址:函数调用期间,实参将地址值,拷贝一份给形参。 【重点】
            (地址值 --》 在swap函数栈帧内部,修改了main函数栈帧内部的局部变量值)

-------------------------------------------------------------------------------------------------
//栈帧:当调用函数时,系统会在stack空间申请一块内存区域,用来供函数调用,主要存放形参和局部变量
// 当函数调用结束,这块内存区域自动被释放
//swap1函数过程梳理:
//1.调用main函数,系统为main函数在stack空间申请一块内存区域,main函数定义了2个变量m/n
//2.main函数运行期间,调用自定义swap1函数,系统为swap1函数申请一块内存区域,实参传递给形参【m/n的值复制给形参a/b】
//(所以在函数调用期间进行数据交换,不影响位于swap1函数外部的变量m/n)
//3.swap1函数调用结束,占用的内存被释放
//4.回到main函数

int swap1(int a, int b) {
    int tmp;
    printf("swap函数:a = %p;b= %p\n", &a, &b);    //swap函数:a = 000000B1C453F760; b = 000000B1C453F768  
    tmp = a;
    a = b;
    b = tmp;
    return 0;    //在swap函数内部,a/b确实进行了数据交换
}

//swap2函数过程梳理:
//1.调用main函数,系统为main函数在stack空间申请一块内存区域,main函数定义了2个变量m/n
//2.main函数调用swap2函数,传入2个地址,
//3.swap2进行接收,在swap2函数的内存空间创建了2个指针变量a,b,并保存了传入的2个地址
//4.swap2函数对2个指针变量进行解引用操作,修改了m,n的数据。swap2函数调用结束,释放内存空间
//5.main函数继续运行,直到结束
//经过验证,main函数的m,n数据确实被调换了
int swap2(int* a, int* b) {
    int tmp;
    tmp = *a;        //此时a,b就是指针变量,里面保存了m,n的内存地址
    *a = *b;
    *b = tmp;
}
int main()
{
    int m = 11, n = 22;
    printf("交换前m = %p;n= %p\n", &m, &n);        //交换前m = 000000B1C453F784;n= 000000B1C453F7A4
    swap1(m,n);
    printf("交换后m = %d;n= %d\n", m, n);        //虽然swap函数进行了数据交换,但是不影响m/n,m/n的值无变化
    swap2(&m, &n);
    printf("swap2交换后m = %d;n= %d\n", m, n);        //swap2交换后m = 22;n= 11;数据发生了交换
}
指针和函数;传数值和传地址;函数形参改变实参的值
复制代码

 

复制代码
数组名作为函数参数;指针做为函数的返回值;数组做函数返回值
========================================================================================================
数组名作为函数参数
    数组名做函数参数,函数的形参会退化为指针
    
//数组做参数时,传递的不是数组,而是数组首地址
//所以数组做函数参数时,一般要传递2个参数,1个地址,1个数组元素数量;
//数组作为函数参数时,存在3种写法:int sort1(int *arr) ;int sort1(int arr[]);int sort1(int arr[10])
int sort1(int arr[],int len) {                            //等效于int sort1(int *arr) 
    int tmp;
    //int len1 = sizeof(arr) / sizeof(arr[0]);        //这种方式求len存在问题,此时arr就是一个指针,sizeof(arr) 求的指针的长度,而不是数组的长度
    for (size_t i = 0; i < 10 -1; i++)
    {
        for (size_t j = 0; j < 10 - i -1; j++) {
            if (arr[j] < arr[j + 1]) {
                tmp = arr[j];
                arr[j] = arr[j +1];
                arr[j+1] = tmp;
            };
        };
    };
}

int main()
{
    int arr[] = { 18,32,773,4444,45,6,997,888,74239,63420 };
    sort1(arr,sizeof(arr) / sizeof(arr[0]));
    for (size_t i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
    {
        printf("%d ", arr[i]);
    };
}
----------------------------------------------------------------------------------------------------
指针做函数返回值
//指针做函数返回值
//不能返回局部变量的地址!!!
int *test(int a) {                             
    a = 333;
    return &a;
}
int main()
{
    int m = 11;
    printf("%p\n", test(m));    //000000D3854FF630
    printf("%d\n", *test(m));    //333    虽然test函数内存地址被回收了,但是内容没有被改变,所以仍然可以打印出来;这种方式显然是不安全的
}

----------------------------------------------------------------------------------------------------
数组做函数返回值
    C语言中,不允许数组作为函数的返回值;只能写成指针形式
    
数组名作为函数参数;指针做为函数的返回值;数组做函数返回值
复制代码

 

指针和字符串

 

复制代码
指针方式定义字符串数组;(练习)实现字符串比较功能;(练习)字符串去空格;(练习)统计字符串2 在字符串1 出现的次数
========================================================================================================
int main()
{
    char str1[] = "hello";
    char* str2 = "hello2";    //这种方式定义出来的是字符串常量!
    
    str1[0] = 'H';
    str2 = str1;

    printf("%s\n", str1);    //Hello
    printf("%s\n", str2);    //Hello
    printf("===============================================================\n");
    char* str3 = "hello3";
    char* str4 = "hello3";
    printf("%p\n", str3);    //00007FF697BF9C24,因为是常量,可以共用;所以str4没有去开辟新的内存空间
    printf("%p\n", str4);    //00007FF697BF9C24
}

------------------------------------------------------------------------------------------------------
实现字符串比较功能
int func1(char arr1[], int len1 , char arr2[], int len2) {
    int len;
    len = len1 > len2 ? len2 : len1;
    for (size_t i = 0; i < len; i++)
    {
        if (*arr1 > *arr2) {    //if (arr1[i] > arr2[i])
            return 1;
        }
        else if (*arr1 < *arr2) {
            return -1;
        }
        else {
            arr1++;
            arr2++;
        }
    }
    return 0;
}

int main()
{
    char str1[] = "hello41";
    char str2[] = "hello51";
    int abc = func1(str1, sizeof(str1) / sizeof(str1[0]), str2, sizeof(str2) / sizeof(str2[0]));
    printf("%d", abc);
}
------------------------------------------------------------------------------------------------------
//字符串去空格
int func1(char arr1[]) {
    char* p = arr1;
    while (*arr1) {
        if (*arr1 != ' ') {
            *p = *arr1;
            p++;
            arr1++;
        }
        else {
            arr1++;
        }
    }
    *p = '\0';
}

int main()
{
    char str1[] = "     h   e   l   l   o  4   1";
    func1(str1);
    printf("%s", str1);
}
------------------------------------------------------------------------------------------------------
(练习)统计字符串2 在字符串1 出现的次数

int my_strstr(char arr1[],char arr2[] ) {
    //视频思路是在使用strstr函数的基础上- -,,,,
    //我的思路,使用指针在两个字符串逐个比较字符,并设置了标志位flag
    //单个字符相同,则flag++,不同则将flag置0;若连续相同,flag位等于5,则判断存在一个相同字符串,count+1,同时将flag置0
    int arr2_len = 0;
    while (arr2[arr2_len]) {
        arr2_len++;        //只要arr2字符串数组的元素不为‘\n’,arr2_len++
    }
    printf("arr2_len:%d\n", arr2_len);
    int count = 0;
    int flag = 0;
    while (*arr1) {
        if (*arr1 == *(arr2 + flag)) {
            flag++;
        }
        else {
            flag = 0;
        }
        if (flag == arr2_len) {
            count++;
            flag = 0;
        }
        arr1++;
    }
    return count;
}
int main()
{
    char arr1[] = "hellollollololollollollollo";
    char arr2[] = "llo";
    int a = my_strstr(arr1, arr2);
    printf("%d\n", a);
}
指针方式定义字符串数组;(练习)实现字符串比较功能;(练习)字符串去空格;(练习)统计字符串2 在字符串1 出现的次数
复制代码

 

复制代码
指针数组做为main函数的形参
========================================================================================================
指针数组做为main函数的形参
int main(int argc, char *argv[]);
    main函数是操作系统调用的,第一个参数标明argc数组的成员数量,argv数组的每个成员都是char *类型
    argv是命令行参数的字符串数组
    argc代表命令行参数的数量,程序名字本身算一个参数




main函数
    无参数:int main(void) == int main()
    有参数:int main(int arg1,char *arr[]) == int main(int arg1,char **arr[) 【固定写法】
        参数1:表示给main函数传递的参数总个数
        参数2:一个指针数组,每一个数组元素都是字符串 char *

//带参数的main函数
int main(int argc, char* argv[])
{
    for (size_t i = 0; i < argc; i++)
    {
        printf("%s   %p\n", argv[i], &argv[i]);
    }
}
/*
C:\Users\Allen\source\repos\C_day01\x64\Debug>C_day01.exe 1 22 333 4444
C_day01.exe   000001B741B25D20
1      000001B741B25D28
22     000001B741B25D30
333    000001B741B25D38
4444   000001B741B25D40
*/
指针数组做为main函数的形参
复制代码

 

复制代码
字符串处理函数:strlen、strcpy、strncpy、strcat、strncat、strcmp、strncmp、sprintf、sscanf、strchr、strstr、strtok、atoi、atof、atol
=======================================================================================
strlen()    
    #include <string.h>
    size_t strlen(const char *s);
    功能:计算指定指定字符串s的长度,不包含字符串结束符‘\0’
    参数:
    s:字符串首地址
    返回值:字符串s的长度,size_t为unsigned int类型

-----------------------------------------------------------------------------------------
strcpy()
    #include <string.h>
    char *strcpy(char *dest, const char *src);
    功能:把src所指向的字符串复制到dest所指向的空间中,'\0'也会拷贝过去
    参数:
        dest:目的字符串首地址
        src:源字符首地址
    返回值:
        成功:返回dest字符串的首地址
        失败:NULL
    注意:如果参数dest所指的内存空间不够大,可能会造成缓冲溢出的错误情况。

-----------------------------------------------------------------------------------------
strncpy()
    #include <string.h>
    char *strncpy(char *dest, const char *src, size_t n);
    功能:把src指向字符串的前n个字符复制到dest所指向的空间中,是否拷贝结束符看指定的长度是否包含'\0'。
    参数:
        dest:目的字符串首地址
        src:源字符首地址
        n:指定需要拷贝字符串个数
    返回值:
        成功:返回dest字符串的首地址
        失败:NULL

-----------------------------------------------------------------------------------------
strcat()
    #include <string.h>
    char *strcat(char *dest, const char *src);
    功能:将src字符串连接到dest的尾部,‘\0’也会追加过去
    参数:
        dest:目的字符串首地址
        src:源字符首地址
    返回值:
        成功:返回dest字符串的首地址
        失败:NULL

-----------------------------------------------------------------------------------------
strncat()
    #include <string.h>
    char *strncat(char *dest, const char *src, size_t n);
    功能:将src字符串前n个字符连接到dest的尾部,‘\0’也会追加过去
    参数:
        dest:目的字符串首地址
        src:源字符首地址
        n:指定需要追加字符串个数
    返回值:
        成功:返回dest字符串的首地址
        失败:NULL

-----------------------------------------------------------------------------------------
strcmp()
    #include <string.h>
    int strcmp(const char *s1, const char *s2);
    功能:比较 s1 和 s2 的大小,比较的是字符ASCII码大小。
    参数:
        s1:字符串1首地址
        s2:字符串2首地址
    返回值:
        相等:0
        大于:>0 在不同操作系统strcmp结果会不同   返回ASCII差值
        小于:<0

-----------------------------------------------------------------------------------------
strncmp()
    #include <string.h>
    int strncmp(const char *s1, const char *s2, size_t n);
    功能:比较 s1 和 s2 前n个字符的大小,比较的是字符ASCII码大小。
    参数:
        s1:字符串1首地址
        s2:字符串2首地址
        n:指定比较字符串的数量
    返回值:
        相等:0
        大于: > 0
        小于: < 0

-----------------------------------------------------------------------------------------
sprintf()
    #include <stdio.h>
    int sprintf(char *str, const char *format, ...);
    功能:根据参数format字符串来转换并格式化数据,然后将结果输出到str指定的空间中,直到出现字符串结束符 '\0'  为止。
    参数:
        str:字符串首地址
        format:字符串格式,用法和printf()一样
    返回值:
        成功:实际格式化的字符个数
        失败: - 1

-----------------------------------------------------------------------------------------
sscanf()
    #include <stdio.h>
    int sscanf(const char *str, const char *format, ...);
    功能:从str指定的字符串读取数据,并根据参数format字符串来转换并格式化数据。
    参数:
        str:指定的字符串首地址
        format:字符串格式,用法和scanf()一样
    返回值:
        成功:参数数目,成功转换的值的个数
        失败: - 1

-----------------------------------------------------------------------------------------
strchr()
    #include <string.h>
    char *strchr(const char *s, int c);
    功能:在字符串s中查找字母c出现的位置
    参数:
        s:字符串首地址
        c:匹配字母(字符)
    返回值:
        成功:返回第一次出现的c地址
        失败:NULL

-----------------------------------------------------------------------------------------
strstr()
    #include <string.h>
    char *strstr(const char *haystack, const char *needle);
    功能:在字符串haystack中查找字符串needle出现的位置
    参数:
        haystack:源字符串首地址
        needle:匹配字符串首地址
    返回值:
        成功:返回第一次出现的needle地址
        失败:NULL

-----------------------------------------------------------------------------------------
strtok()
    #include <string.h>
    char *strtok(char *str, const char *delim);
    功能:来将字符串分割成一个个片段。当strtok()在参数s的字符串中发现参数delim中包含的分割字符时, 则会将该字符改为\0 字符,当连续出现多个时只替换第一个为\0。
    参数:
        str:指向欲分割的字符串
        delim:为分割字符串中包含的所有字符
    返回值:
        成功:分割后字符串首地址
        失败:NULL

-----------------------------------------------------------------------------------------
atoi()
    #include <stdlib.h>
    int atoi(const char *nptr);
    功能:atoi()会扫描nptr字符串,跳过前面的空格字符,直到遇到数字或正负号才开始做转换,而遇到非数字或字符串结束符('\0')才结束转换,并将结果返回返回值。
    参数:
        nptr:待转换的字符串
    返回值:成功转换后整数

类似的函数有:
    atof():把一个小数形式的字符串转化为一个浮点数。
    atol():将一个字符串转化为long类型
字符串处理函数:strlen、strcpy、strncpy、strcat、strncat、strcmp、strncmp、sprintf、sscanf、strchr、strstr、strtok、atoi、atof、atol
复制代码

 

posted @   雲淡風輕333  阅读(118)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示