• C语言学习之路(基础篇)—— 指针(下)


    说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!

    指针和函数

    1) 函数形参改变实参的值

    示例1:整型变量作为函数的形参,无法改变实参的值

    #include 
    
    void swap(int a, int b) {
    
    	int c;
    	c = a;
    	a = b;
    	b = c;
    	printf("a=%d, b=%d\n", a, b);
    	return;
    }
    
    int main() {
    
    	int a = 10;
    	int b = 20;
    	swap(a, b);
    	printf("a=%d, b=%d\n", a, b);
    
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    输出结果
    a=20, b=10
    a=10, b=20
    
    • 1
    • 2
    • 3

    示例2:指针变量作为函数的形参,可以改变实参的值

    #include 
    
    void swap(int a, int b) {
    
    	int c;
    	c = a;
    	a = b;
    	b = c;
    	printf("a=%d, b=%d\n", a, b);
    	return;
    }
    void swap2(int *x, int *y) {
    	
    	int c = *x;
    	*x = *y;
    	*y = c;
    	printf("c=%d x=%d, y=%d\n", c, *x, *y);
    	return;
    }
    int main() {
    
    	int a = 10;
    	int b = 20;
    	//swap(a, b);
    	swap2(&a, &b);
    	printf("a=%d, b=%d\n", a, b);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    在这里插入图片描述

    输出结果
    c=10 x=20, y=10
    a=20, b=10
    
    • 1
    • 2
    • 3

    2) 数组名做函数参数

    数组名做函数参数,函数的形参会退化为指针。

    #include 
    
    // 数组作为函数的形参会退化为指针
    // 形参int b[10]就退化成int *b,哪怕形参是int b[10000],也是int *b
    void printf_arr(int b[10]) {
    
    	// 这里sizeof(b)==sizeof(int)==4个字节
    	// sizeof(b[0])其中b[0] == int *(b+0) == int *b == a == 3,所以sizeof(b[0]) == sizeof(3) == sizeof(int)==4个字节
    	int len = sizeof(b) / sizeof(b[0]); // 4/4=1
    	for (int i = 0; i < len; i++)
    	{
    		printf("%d ", b[i]); // 3
    	}
    
    
    	return 0;
    }
    
    int main() {
    
    	int a[10] = { 3,9,5,1,4,7,6,10,2,8 };
    	printf_arr(a); // 实参a为数组名,也就是首元素地址 &a[0], 类型为int*类型
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    那么就需要传递数组元素个数,让printf_arr函数知道,才能打印数组其他元素

    #include 
    
    // 数组作为函数的形参会退化为指针
    // 形参int b[10]就退化成int *b,哪怕形参是int b[10000],也是int *b
    void printf_arr(int b[10], int len) {
    
    	// 这里sizeof(b)==sizeof(int)==4个字节
    	// sizeof(b[0])其中b[0] == int *(b+0) == int *b == a == 3,所以sizeof(b[0]) == sizeof(3) == sizeof(int)==4个字节
    	//int len = sizeof(b) / sizeof(b[0]); // 4/4=1
    	for (int i = 0; i < len; i++)
    	{
    		printf("%d ", b[i]); // 3
    	}
    
    
    	return 0;
    }
    
    int main() {
    
    	int a[10] = { 3,9,5,1,4,7,6,10,2,8 };
    	int len = sizeof(a) / sizeof(a[0]);
    	printf_arr(a, len); // 实参a为数组名,也就是首元素地址 &a[0], 类型为int*类型
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    3) 指针做为函数的返回值

    #include 
    #include 
    #include 
    
    int* getNum() {
    	// srand()用来设置rand()产生随机数时的随机种子
    	srand(time(0));
    	int num = rand();
    	return &num;
    
    }
    
    int main() {
    
    	int* p = getNum();
    
    	printf("%d\n", *p);
    
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    补充:在函数中定义的变量叫局部变量,局部变量一旦在函数结束之后就会被释放空间,所以在getNum函数return后,再去main函数中操作这块被释放空间是非法的,但是编译器不会告诉我们,这块空间没有被占用,所以不会出问题,但如果被占用,那么就会出错。

    在函数外面定义的变量叫全局变量,整个工程都可以使用;整个变量程序启动开辟空间,直到程序结束才会释放空间。

    #include 
    #include 
    #include 
    // 在函数外面定义的变量叫全局变量,整个工程都可以使用
    // 整个变量程序启动开辟空间,直到程序结束释放空间
    int num = 0;
    
    int* getNum() {
    	// srand()用来设置rand()产生随机数时的随机种子
    	srand(time(0));
    	//{}中定义的变量叫局部变量,局部变量一旦在函数结束之后就会被释放空间
    	//int num = rand();
    	num = rand();
    	return &num;
    
    }
    
    int main() {
    
    	int* p = getNum();
    
    	printf("%d\n", *p);
    
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    指针和字符串

    1) 字符指针

    示例1:

    #include 
    
    int main() {
    	//指针与字符串
    	char str[] = "cdtaogang"; //定义了一个字符数组,字符数组内容为cdtaogang\0
    	//定义一个指针用来保存数组首元素的地址
    	char* p = str;
    	printf("%s\n", p); //%s打印一个字符串,要的是首个字符的地址
    	printf("%s\n", p+2);
    	printf("%c\n", *(p + 3));
    	printf("%d\n", sizeof(str));
    	printf("%d\n", sizeof(p));
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    输出结果
    cdtaogang
    taogang
    a
    10
    4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    示例2:

    #include 
    
    int main() {
    	//指针与字符串
    	char str[] = "cdtaogang"; //定义了一个字符数组,字符数组内容为cdtaogang\0
    	//定义一个指针用来保存数组首元素的地址
    	char* p = str;
    	*p = 'N';
    	p++;
    	*p = 'B';
    	p++;
    	printf("%s\n", p);
    	printf("%s\n", p-2);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    输出结果
    taogang
    NBtaogang
    
    • 1
    • 2
    • 3

    2) 字符串常量

    • 字符串常量是不可以改变的,存在文字常量区
    • 文字常量区的内容是不可以改变的
    • char *p = "hello"; 代表将字符串常量的地址赋值给指针p

    示例:

    #include 
    #include 
    
    int main() {
    
        char  str[] = "helloworld";//定义了一个字符数组,字符数组内容为helloworld
                                                          //定义一个指针用来保存数组首元素的地址
        char* p = str;
        p = "abcdef";//字符串常量存文字常量区,""在使用时,取的是字符串首元素的地址
        printf("%s\n", p); // abcdef
        printf("%d\n", sizeof(p));//4
        printf("%d\n", sizeof("abcdef"));//7   abcdef\0
        printf("%d\n", strlen(p));//6
        printf("%d\n", strlen("abcdef"));//6  strlen返回字符串长度
        //文字常量区的内容是不可以改变的
        p = 'm';
        printf("%s\n", p); 
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    输出结果
    abcdef
    4
    7
    6
    6
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3) 字符指针做函数参数

    示例1:

    #include 
    #include 
    
    void mystrcat(char* dst, char* src)
    {
    	int n = strlen(dst);
    	int i = 0;
    	while (*(src + i)!=0)
    	{
    		*(dst+n) = *(src + i);
    		i++;
    		n++;
    	}
    	*(dst + n) = 0;
    }
    
    int main()
    {
    	char str1[128] = "hello ";
    	char str2[128] = "cdtaogang";
    
    	mystrcat(str1, str2); // 不用传递元素个数,因为字符数组最后一个元素为\0,可以以此作为判断
    	printf("%d\n", strlen(str1));
    	printf("%d\n", sizeof(str1));
    	printf("str1 = %s", str1); 
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    输出结果
    15
    128
    str1 = hello cdtaogang
    
    • 1
    • 2
    • 3
    • 4

    示例2:

    #include 
    
    void mystrcat(char* dst, const char* src)
    {
    	int len1 = 0;
    	int len2 = 0;
    	// 遍历数组计算元素个数
    	while (dst[len1])
    	{
    		len1++;
    	}
    	while (src[len2])
    	{
    		len2++;
    	}
    
    	int i;
    	for (i = 0; i < len2; i++)
    	{
    		dst[len1 + i] = src[i];
    	}
    }
    
    int main()
    {
    	char str1[100] = "hello ";
    	char str2[] = "cdtaogang";
    
    	mystrcat(str1, str2);
    	printf("str1 = %s\n", str1);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    输出结果
    str1 = hello cdtaogang
    
    • 1
    • 2

    4) const修饰的指针变量

    • const修饰一个变量为只读
    • const修饰指针,不能通过指针修改指针所指向的空间内容
    • const修饰指针变量,在初始化之后不能改变指针变量本身的指向
    #include 
    #include 
    #include 
    
    int main(void)
    {
    	//const修饰一个变量为只读
    	const int a = 10;
    	//a = 100; //err
    
    	//指针变量, 指针指向的内存, 2个不同概念
    	char buf[] = "cdtaogang";
    
    	//从左往右看,跳过类型,看修饰哪个字符
    	//如果是*, 说明指针指向的内存不能改变
    	//如果是指针变量,说明指针的指向不能改变,指针的值不能修改
    	
    	// const修饰指针,不能通过指针修改指针所指向的空间内容,但p变量本身的值是可以被修改的
    	const char* p = buf; 
    	// 等价于上面 char const *p1 = buf;
    	//p[1] = '2'; //err // 不能通过p指针修改那块空间的内容
    	p = "agdlsjaglkdsajgl"; //ok
    
    	// const修饰指针变量p2初始化之后不能改变p2指针变量本身的指向
    	char* const p2 = buf;
    	p2[1] = '3';
    	//p2 = "salkjgldsjaglk"; //err // 不能改变p2指针变量本身的指向
    
    	// const修饰指针和指针变量,p3为只读,指向不能变,指向的内存也不能变
    	const char* const p3 = buf;
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    5) 字符指针数组 *

    字符指针数组:是一个数组,每一个元素都是字符指针。

    示例1:

    #include 
    //字符指针数组
    int main() {
    	char* p1 = "hello";
    	char* p2 = "hi";
    	char* p3 = "hey";
    	//char* str[3] = { p1, p2,p3 };
    	char* str[3] = { "hello", "hi","hey" };
    	for (int i = 0; i < 3; i++)
    	{	
    		printf("%s ", str[i]);
    	}
    	printf("\n");
    	// 打印首元素的值
    	printf("%c\n", *str[0]);
    	// 打印字符串hi中的i
    	printf("%c\n", *(str[1] + 1));
    	// 打印字符串hey中的y
    	printf("%c\n", *(str[2] + 2));
    	// 打印字符指针数组所有元素中的e字符
    	for (int i = 0; i < sizeof(str); i++)
    	{	
    		for (int j = 0; j < strlen(str[i]); j++)
    		{
    			if (str[i][j] == 'e')
    			{
    				printf("%c\n", str[i][j]);
    			}
    		}
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述

    输出结果
    hello hi hey
    h
    i
    y
    e
    e
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    示例2:

    #include 
    
    int main() {
    
    	char* str[3] = { "hello", "hi","hey" };
    	//定义一个指针保存str数组首元素的地址
    	char** p = str;  // &str[0] == str
    
    	for (int i = 0; i < 3; i++)
    	{
    		printf("%s", *(p+i));
    		printf("%s\n", p[i]);
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    输出结果
    hellohello
    hihi
    heyhey
    
    • 1
    • 2
    • 3
    • 4

    示例3:

    #include 
    
    int main() {
    
    	char* str[3] = { "hello", "hi","hey" };
    	//定义一个指针保存str数组首元素的地址
    	char** p = str;  // &str[0] == str
    	
    	// 通过指针p取出首元素的值
    	printf("%c", *(*(p + 0))); // *(p+0)得到str[0]里面的内容0x1000,而0x1000又代表hello\0首元素地址,所以取首元素的值就是*(*(p+0))
    	printf("%c", *(p[0]+0)); // 上一步简写
    	printf("%c", p[0][0]); // 再简写
    	// 通过指针p取出数组元素hey中的e字符
    	printf("%c", *(*(p + 2) + 1)); // *(p+2)得到str[2]里面的内容0x3000,而0x3000又代表hey\0首元素地址,在首元素地址上+1即*(p+2)+1就得到e字符的地址,所以取e字符就是*(*(p+2)+1)
    	printf("%c", *(p[2] + 1));
    	printf("%c", p[2][1]);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    6) 指针数组做为main函数的形参

    int main(int argc, char *argv[]);
    
    • 1
    • main函数是操作系统调用的,第一个参数标明argc数组的成员数量,argv数组的每个成员都是char *类型
    • argv是命令行参数的字符指针数组,保存的是参数(字符串)的首元素地址
    • argc代表命令行参数的数量,程序名字本身算一个参数
    #include 
    
    //argc: 传参数的个数(包含可执行程序)
    //argv:指针数组,指向输入的参数
    // .*.exe   hello  123456
    int main(int argc, char* argv[])
    {
    	// 打印运行参数
    	printf("%d\n", argc);
    	printf("%s\n", argv[0]);
    	printf("%s\n", argv[1]);
    	printf("%s\n", argv[2]);
    	printf("%s\n", argv[3]);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    右击项目>属性,配置调试命令参数 hello 123456

    在这里插入图片描述

    相当于char* argv[] = {".*.exe", "hello", "123456"},传参不够后,打印取值为null

    在这里插入图片描述

    通过argc的值,就能知道传参个数,所以可以通过for循环来打印输入的参数;需要注意的是在命令行参数之前还有.*.exe程序路径

    #include 
    
    //argc: 传参数的个数(包含可执行程序)
    //argv:指针数组,指向输入的参数
    // .*.exe   hello  123456
    // char* argv[] = {".*.exe", "hello", "123456"}
    int main(int argc, char* argv[])
    {
    	for (int i = 0; i <argc; i++)
    	{
    		printf("%s\n", argv[i]);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    输出结果
    E:\VisualStudioProjects\StudyCProject\Debug\StudyCProject.exe
    hello
    123456
    
    • 1
    • 2
    • 3
    • 4

    我们可以通过gcc命令编译生成exe可执行程序来执行命令行参数的打印

    #include 
    // 形参名随便取
    int main(int n, char *v[]){
    	
    	for(int i = 0; i < n; i++)
    	{
    		printf("%s\n", v[i]);
    	}
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    PS C:\Users\Administrator\Desktop> gcc hello.c -o hello
    PS C:\Users\Administrator\Desktop> ./hello.exe hello CSDN cdtaogang good good study
    
    • 1
    • 2

    在这里插入图片描述

    7) 字符串处理函数

    7.1 strcpy()

    拷贝字符串:

    • 表头文件:#include
    • 定义函数:char *strcpy(char *dest, const char *src);
    • 功能:把src所指向的字符串复制到dest所指向的空间中,'\0'也会拷贝过去
    • 参数:
      dest:目的字符串首地址
      src:源字符首地址
    • 返回值:
      成功:返回dest字符串的首地址
      失败:NULL

    注意:如果参数dest所指的内存空间不够大,可能会造成缓冲溢出的错误情况。

    示例1:

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    int main() {
    	// strcpy函数
    	char str1[128] = "";
    	char str2[128] = "cdtaogang";
    	char str3[128] = "hello\0cdtaogang";
    	char str4[128] = "csdn";
    	strcpy(str1, str2);
    	printf("%s\n", str1); // cdtaogang
    	strcpy(str1, str3); // 遇到 '\0'就结束拷贝
    	printf("%s\n", str1); // hello
    	strcpy(str2, str4); // csdn后面的'\0'也会拷贝过去,遇到'\0'结束掉相当于替换掉原始数据
    	printf("%s\n", str2); // csdn
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    输出结果
    cdtaogang
    hello
    csdn
    
    • 1
    • 2
    • 3
    • 4

    7.2 strncpy()

    拷贝字符串:

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

    示例1:

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    int main() {
    	// strncpy函数
    	char str1[128] = "";
    	char str2[128] = "hellocdtaogang";
    	char str3[128] = "he\0llocdtaogang";
    
    	strncpy(str1, str2, 2);
    	printf("str1=%s\n", str1); // he
    
    	strncpy(str1, str2, 5);
    	printf("str1=%s\n", str1); // hello
    
    	strncpy(str1, str3, 5);
    	printf("str1=%s\n", str1); // he
    	// 验证将将str3字符串前5个字符拷贝至str1中是 he\0\0\0 还是 he\0wl
    	for (int i = 0; i < 5; i++)
    	{
    		printf("%d ", str1[i]); // 104 101 0 0 0 说明拷贝的情况是不足n个字符就遇到了\0那么后面就不拷贝了
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    输出结果
    str1=he
    str1=hello
    str1=he
    104 101 0 0 0
    
    • 1
    • 2
    • 3
    • 4
    • 5

    7.3 strcat()

    连接两字符串:

    • 表头文件:#include
    • 定义函数:char *strcat(char *dest, const char *src);
    • 功能:将src字符串连接到dest的尾部,‘\0’也会追加过去
    • 参数:
      dest:目的字符串首地址
      src:源字符首地址
    • 返回值:
      成功:返回dest字符串的首地址
      失败:NULL

    示例1:

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    int main() {
       // strcat函数
       char str1[128] = "hello";
       char str2[128] = "cdtaogang";
       char str3[128] = "world\0ocdtaogang";
    
       strcat(str1, str2);
       printf("str1=%s\n", str1); // hellocdtaogang
    
       strcat(str1, str3);
       printf("str1=%s\n", str1); // hellocdtaogangworld
    
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    输出结果
    str1=hellocdtaogang
    str1=hellocdtaogangworld
    
    • 1
    • 2
    • 3

    7.4 strncat()

    连接两字符串:

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

    示例1:

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    int main() {
    	// strncat函数
    	char str1[128] = "hello";
    	char str2[128] = "123456";
    	char str3[128] = "world\0ocdtaogang";
    
    	strncat(str1, str2, 3);
    	printf("str1=%s\n", str1); // hello123
    
    	strncat(str1, str3, 10);
    	printf("str1=%s\n", str1); // hello123world
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    输出结果
    str1=hello123
    str1=hello123world
    
    • 1
    • 2
    • 3

    7.5 strcmp()

    比较字符串:

    • 表头文件:#include
    • 定义函数:int strcmp(const char *s1, const char *s2);
    • 功能:比较 s1s2 的大小,比较的是字符ASCII码大小。
    • 参数:
      s1:字符串1首地址
      s2:字符串2首地址
    • 返回值:
      相等:0
      大于:>0 在不同操作系统strcmp结果会不同 返回ASCII差值
      小于:<0

    示例1:

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    int main() {
    	// strcmp函数
    	char* str1 = "hello world";
    	char* str2 = "hello cdtaogang";
    	char* str3 = "hello cdtaogang";
    	char* str4 = "zzzzzzzzz";
    
    	printf("strcmp(str1, str2):%d\n", strcmp(str1, str2)); // 1
    	printf("strcmp(str2, str3):%d\n", strcmp(str2, str3)); // 0
    	printf("strcmp(str2, str4):%d\n", strcmp(str2, str4)); // -1
    
    	if (strcmp(str1, str2) == 0)
    	{
    		printf("str1==str2\n");
    	}
    	else if (strcmp(str1, str2) > 0)
    	{
    		printf("str1>str2\n");
    	}
    	else  // < 0
    	{
    		printf("str1);
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    输出结果
    strcmp(str1, str2):1
    strcmp(str2, str3):0
    strcmp(str2, str4):-1
    str1>str2
    
    • 1
    • 2
    • 3
    • 4
    • 5

    7.6 strncmp()

    比较字符串:

    • 表头文件:#include
    • 定义函数:int strncmp(const char *s1, const char *s2, size_t n);
    • 功能:比较 s1s2n个字符的大小,比较的是字符ASCII码大小。
    • 参数:
      s1:字符串1首地址
      s2:字符串2首地址
      n:指定比较字符串的数量
    • 返回值:
      相等:0
      大于:>0
      小于:<0

    示例1:

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    int main() {
    	// strncmp函数
    	char* str1 = "hello world";
    	char* str2 = "hello cdtaogang";
    	char* str3 = "hello cdtaogang";
    	char* str4 = "zzzzzzzzz";
    
    	printf("strncmp(str1, str2, 7):%d\n", strncmp(str1, str2, 7)); // 1
    	printf("strncmp(str2, str3, 6):%d\n", strncmp(str2, str3, 6)); // 0
    	printf("strncmp(str2, str4, 1):%d\n", strncmp(str2, str4, 1)); // -1
    
    	if (strncmp(str1, str2, 8) == 0)
    	{
    		printf("str1==str2\n");
    	}
    	else if (strncmp(str1, str2, 8) > 0)
    	{
    		printf("str1>str2\n");
    	}
    	else  // < 0
    	{
    		printf("str1);
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    输出结果
    strncmp(str1, str2, 7):1
    strncmp(str2, str3, 6):0
    strncmp(str2, str4, 1):-1
    str1>str2
    
    • 1
    • 2
    • 3
    • 4
    • 5

    7.7 sprintf()

    格式化字符串复制(组包函数)

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

    示例1:

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    int main() {
    	// sprintf函数
    	int year = 2022;
    	int month = 11;
    	int day = 19;
    
    	//printf("today is %d-%d-%d\n", year, month, day);
    
    	char buf[1024] = "";
    	char buf2[1024] = "";
    	sprintf(buf, "today is %d-%d-%d\n", year, month, day); // 将数据安装格式组包,存放在数组buf中,sprintf函数的返回值是组完包的有效长度
    	printf("buf=[%s]\n", buf); // buf=[today is 2022-11-19
                                   //]
    	// 打印buf字符个数
    	int len2 = sprintf(buf2, "to%cday is %d-%d-%d\n", 0, year, month, day);
    	printf("%d\n", strlen(buf2)); // 2  strlen遇到0就结束了,所以字符个数不准确
    	printf("len=%d\n", len2); // len=21
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    输出结果
    buf=[today is 2022-11-19
    ]
    2
    len=21
    
    • 1
    • 2
    • 3
    • 4
    • 5

    7.8 sscanf()

    格式化字符串输入(拆包函数)

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

    示例1:

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    int main() {
    	// sscanf函数
    	int year;
    	int month;
    	int day;
    
    	//scanf("%d-%d-%d", &year, &month, &day);// 从键盘按照相应的格式获取数据
    	char buf[1024] = "beijing:2022-11-19";
    	sscanf(buf, "beijing:%d-%d-%d", &year, &month, &day); // 从buf中按照相应的格式获取数据
    	printf("today is %d-%d-%d", year, month, day);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    输出结果
    today is 2022-11-19
    
    • 1
    • 2

    7.9 strchr()

    查找字符串中第一个出现的指定字符

    • 表头文件:#include
    • 定义函数:char *strchr(const char *s, int c);
    • 功能:在字符串s中查找字母c出现的位置
    • 参数:
      s:字符串首地址
      c:匹配字母(字符)
    • 返回值:
      成功:返回第一次出现的c地址
      失败:NULL

    示例1:

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    int main() {
    	// 编写代码实现第一次出现a字符的地址
    	char src[] = "ddda123abcd";
    	int i = 0;
    	char* p = src;
    	while (p[i]!=0)
    	{
    		if (p[i] == 'a')
    		{
    			p = &p[i];
    			break;
    		}
    		i++;
    	}
    	printf("p = %s\n", p);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    示例2:

    char *my_strchr(char* p, char ch) {
    
    	int i = 0;
    	while (p[i]!=0)
    	{
    		if (p[i]==ch)
    		{
    			return &p[i];
    		}
    		i++;
    	}
    	return NULL;
    }
    int main() {
    	// 定义函数实现
    	char src[] = "ddda123abcd";
    	char* p = my_strchr(src, 'a');
    	printf("p = %s\n", p);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    示例3:

    int main() {
    	// strchr函数
    	char src[] = "ddda123abcd";
    	char* p = strchr(src, 'a');
    	printf("p = %s\n", p);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    7.10 strstr()

    在一字符串中查找指定的字符串

    • 表头文件:#include
    • 定义函数:char *strstr(const char *haystack, const char *needle);
    • 功能:在字符串haystack中查找字符串needle出现的位置
    • 参数:
      haystack:源字符串首地址
      needle:匹配字符串首地址
    • 返回值:
      成功:返回第一次出现的needle地址
      失败:NULL

    示例1:

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    char* my_strstr(char* str1, char *str2) {
    
    	int i = 0;
    	// str[i] == *(str+i)
    	while (str1[i] != 0)
    	{
    		if (str1[i] == str2[0])
    		{	// str1+i就表示str1中'a'的地址
    			if (0==strncmp(str1+i, str2, strlen(str2)))
    			{
    				return str1+i;
    			}
    		}
    		i++;
    	}
    	return NULL;
    }
    int main() {
    	// 定义函数实现
    	char str1[] = "ddddabcd123abcd333abcd";
    	char str2[] = "abcd";
    	char* p = my_strstr(str1, str2);
    	printf("p = %s\n", p);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    示例2:

    int main() {
    	// strstr函数
    	char str1[] = "ddddabcd123abcd333abcd";
    	char str2[] = "abcd";
    	char* p = strstr(str1, str2);
    	printf("p = %s\n", p);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    输出结果
    p = abcd123abcd333abcd
    
    • 1
    • 2

    7.11 strtok()

    分割字符串

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

    示例1:

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    int main() {
    	// strtok函数
    	char str[] = "CSDN#1126331350#cdtaogang#9528";
    	char* p1 = strtok(str, "#");
    	printf("p1=%s\n", p1); // p1=CSDN
    	// strtok会记录每次切割,并将切割部分内部记录为\0,所以第二次及之后的切割从NULL开始往后找
    	char* p2 = strtok(NULL, "#");
    	printf("p2=%s\n", p2); // p2=1126331350
    	char* p3 = strtok(NULL, "#");
    	printf("p3=%s\n", p3); // p3=cdtaogang
    	char* p4 = strtok(NULL, "#");
    	printf("p4=%s\n", p4); // p4=9528
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    示例2:

    int main() {
    	// strtok函数
    	char str[] = "CSDN#1126331350#cdtaogang#9528";
    	// 使用while循环将"#"分割的子串全部取出
    	char* s = strtok(str, "#");
    	while (s != NULL)
    	{
    		printf("%s\n", s);
    		s = strtok(NULL, "#");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    示例3:

    int main() {
    	// strtok函数
    	char str[] = "CSDN#1126331350#cdtaogang#9528";
    	// 使用do while循环将"#"分割的子串全部取出
    	char* p[10] = { NULL };
    	int i = 0;
    	do
    	{
    		if (i == 0) // 表示第一次切割
    		{
    			p[i] = strtok(str, "#");
    		}
    		else
    		{
    			p[i] = strtok(NULL, "#");
    		}
    	} while (p[i++]!=NULL); // i在前先使用再++,即p[0]!=NULL i=i+1 如果strtok的返回值等于NULL,代表切割完毕
    	// 循环打印
    	i = 0;
    	while (p[i++]!=NULL)
    	{
    		printf("%s\n", p[i-1]); // 打印时i已经+1了
    
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    示例4:

    int main() {
    	// strtok函数
    	char str[] = "CSDN#1126&331350#cdtaogang#95&28";
    	// 使用do while循环将"#&"分割的子串全部取出
    	char* p[10] = { NULL };
    	int i = 0;
    	do
    	{
    		if (i == 0) // 表示第一次切割
    		{
    			p[i] = strtok(str, "#&");
    		}
    		else
    		{
    			p[i] = strtok(NULL, "#&");
    		}
    	} while (p[i++]!=NULL); // i在前先使用再++,即p[0]!=NULL i=i+1 如果strtok的返回值等于NULL,代表切割完毕
    	// 循环打印
    	i = 0;
    	while (p[i++]!=NULL)
    	{
    		printf("%s\n", p[i-1]); // 打印时i已经+1了
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

    7.12 atoi()

    将字符串转换为整型数

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

    类似的函数有:

    • atof():把一个小数形式的字符串转化为一个浮点数。
    • atol():将一个字符串转化为long类型

    示例1:

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    int main() {
    	// atoi函数
    	// 0-9的字符和-+号就开始转,如果不是+-0-9的字符就结束,如果前面有空格,就跳过
    	char a[] = "1234";
    	char b[] = "-1234";
    	char c[] = "e1234";
    	char d[] = " 1234";
    	printf("a=%d\n", atoi(a));
    	printf("b=%d\n", atoi(b));
    	printf("c=%d\n", atoi(c));
    	printf("d=%d\n", atoi(d));
    	// atof函数
    	char e[] = "3.14";
    	printf("e=%f\n", atof(e));
    	// atol函数
    	char f[] = "11321321";
    	printf("f=%ld\n", atol(f));
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    输出结果
    a=1234
    b=-1234
    c=0
    d=1234
    e=3.140000
    f=11321321
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    8) 项目开发常用字符串应用模型

    8.1 strstr中的while和do-while模型

    利用strstr标准库函数找出一个字符串中abcd出现的次数。

    while模型

    #include 
    #include 
    
    
    int main() {
    
    	char* p = "32e23abcd11132122abcd333abcd9922abcd333abc32d2qqq";
    	int n = 0;
    	// 查找匹配到到则进去,循环条件第一次从字符串首元素地址开始查找
    	while ((p=strstr(p, "abcd"))!=NULL)
    	{	
    		// 进入循环后,说明此时已经匹配到一个了,那么就要重新设置查找起点位置
    		p += strlen("abcd");
    		n++;
    	}
    	printf("n=%d", n);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    输出结果
    n=4
    
    • 1
    • 2

    do-while模型

    int main() {
    
    	char* p = "32e23abcd11132122abcd333abcd9922abcd333abc32d2qqq";
    	int n = 0;
    	do
    	{
    		p = strstr(p, "abcd");
    		if (p!=NULL)
    		{	
    			p += strlen("abcd");
    			n++;
    		}
    		
    	} while (p!=NULL);
    	printf("n=%d", n);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    输出结果
    n=4
    
    • 1
    • 2

    8.2 两头堵模型

    求非空字符串元素的个数:

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    int main() {
    
    	char str[] = "    hello cdtaogang     ";//hello cdtaogang
        char buf[128] = "";
    	// 判断空字符
        if (str[0] == 0)
    		return;
        char * begin = str; // 数组首元素地址,也就是起始位置
    	// str字符串的长度-1就表示最后一个元素的下标,取最后一个字符的地址
        char *end = &str[strlen(str) - 1];//end指向最后一个字符
        //从起始位置开始找,找到第一个不是空格的位置,并且不能移出数组最后一个位置\0
        while (*begin == ' ' &&  *begin != 0)
        {
    		begin++;
        }
    	//从结束位置开始找,找到第一个不是空格的位置,并且不能等于begin字符串的起始位置
        while (*end == ' '  &&  end != begin)
        {
                end--;
        }
    	// 打印数组的长度,字符结束位置-起始位置+1得到字符串的长度
        printf("%d\n",end-begin +1);
    	// 将匹配出来的字符串拷贝到buf数组中
        strncpy(buf, begin, end-begin +1);
        printf("buf=%s\n", buf);
        system("pause");
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    输出结果
    15
    buf=hello cdtaogang
    
    • 1
    • 2
    • 3

    8.3 字符串反转模型(逆置)

    在这里插入图片描述

    #include 
    
    
    int main() {
    
    	char str[] = "abcdef";
    
    	char* begin = str;
    	char* end = &str[strlen(str) - 1];
    	printf("%c %c\n", *begin, *end);  // a f
    	printf("str=%s\n", str);
    	while (end > begin)
    	{	
    		//交换元素
    		char ch = *begin;
    		*begin = *end;
    		*end = ch;
    		begin++;
    		end--;
    	}
    	printf("str=%s\n", str);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这里插入图片描述

    指针小结

    定义说明
    int i定义整形变量
    int *p定义一个指向int的指针变量
    int a[10]定义一个有10个元素的数组,每个元素类型为int
    int *p[10]定义一个有10个元素的数组,每个元素类型为int*
    int func()定义一个函数,返回值为int型
    int *func()定义一个函数,返回值为int *型
    int **p定义一个指向int的指针的指针,二级指针(即p指向的地址里面存放的是一个指向int的一级指针)
  • 相关阅读:
    WEB前端网页设计 HTML CSS 网页设计参数 - 【浮动与定位】
    The Sandbox 与 T&B Media Global 达成合作
    springboot+学生信息管理 毕业设计-附源码191219
    自动化测试----unittest框架
    5.后端·新建子模块与开发(自动模式)
    c++常用知识
    彻底讲透redo日志磁盘顺序写机制
    SpringMvc与SpringBoot有什么不同?
    【一】1D测量 Measuring——gen_measure_rectangle2()算子
    嵌入式能从事什么职业?
  • 原文地址:https://blog.csdn.net/qq_41782425/article/details/127894938