说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!
指针和函数
1) 函数形参改变实参的值
示例1:整型变量作为函数的形参,无法改变实参的值
#include <stdio.h>
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;
}
输出结果
a=20, b=10
a=10, b=20
示例2:指针变量作为函数的形参,可以改变实参的值
#include <stdio.h>
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;
}
输出结果
c=10 x=20, y=10
a=20, b=10
2) 数组名做函数参数
数组名做函数参数,函数的形参会退化为指针。
#include <stdio.h>
// 数组作为函数的形参会退化为指针
// 形参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;
}
那么就需要传递数组元素个数,让printf_arr函数知道,才能打印数组其他元素
#include <stdio.h>
// 数组作为函数的形参会退化为指针
// 形参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;
}
3) 指针做为函数的返回值
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int* getNum() {
// srand()用来设置rand()产生随机数时的随机种子
srand(time(0));
int num = rand();
return #
}
int main() {
int* p = getNum();
printf("%d\n", *p);
return 0;
}
补充:在函数中定义的变量叫局部变量,局部变量一旦在函数结束之后就会被释放空间,所以在getNum函数return后,再去main函数中操作这块被释放空间是非法的,但是编译器不会告诉我们,这块空间没有被占用,所以不会出问题,但如果被占用,那么就会出错。
在函数外面定义的变量叫全局变量,整个工程都可以使用;整个变量程序启动开辟空间,直到程序结束才会释放空间。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// 在函数外面定义的变量叫全局变量,整个工程都可以使用
// 整个变量程序启动开辟空间,直到程序结束释放空间
int num = 0;
int* getNum() {
// srand()用来设置rand()产生随机数时的随机种子
srand(time(0));
//{}中定义的变量叫局部变量,局部变量一旦在函数结束之后就会被释放空间
//int num = rand();
num = rand();
return #
}
int main() {
int* p = getNum();
printf("%d\n", *p);
return 0;
}
指针和字符串
1) 字符指针
示例1:
#include <stdio.h>
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;
}
输出结果
cdtaogang
taogang
a
10
4
示例2:
#include <stdio.h>
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;
}
输出结果
taogang
NBtaogang
2) 字符串常量
- 字符串常量是不可以改变的,存在文字常量区
- 文字常量区的内容是不可以改变的
char *p = "hello";
代表将字符串常量的地址赋值给指针p
示例:
#include <stdio.h>
#include <string.h>
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;
}
输出结果
abcdef
4
7
6
6
3) 字符指针做函数参数
示例1:
#include <stdio.h>
#include <string.h>
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;
}
输出结果
15
128
str1 = hello cdtaogang
示例2:
#include <stdio.h>
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;
}
输出结果
str1 = hello cdtaogang
4) const修饰的指针变量
const
修饰一个变量为只读const
修饰指针,不能通过指针修改指针所指向的空间内容const
修饰指针变量,在初始化之后不能改变指针变量本身的指向
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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;
}
5) 字符指针数组 *
字符指针数组:是一个数组,每一个元素都是字符指针。
示例1:
#include <stdio.h>
//字符指针数组
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;
}
输出结果
hello hi hey
h
i
y
e
e
示例2:
#include <stdio.h>
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;
}
输出结果
hellohello
hihi
heyhey
示例3:
#include <stdio.h>
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;
}
6) 指针数组做为main函数的形参
int main(int argc, char *argv[]);
main
函数是操作系统调用的,第一个参数标明argc
数组的成员数量,argv
数组的每个成员都是char *
类型argv
是命令行参数的字符指针数组,保存的是参数(字符串)的首元素地址argc
代表命令行参数的数量,程序名字本身算一个参数
#include <stdio.h>
//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;
}
右击项目>属性,配置调试命令参数 hello 123456
相当于char* argv[] = {".*.exe", "hello", "123456"}
,传参不够后,打印取值为null
通过argc
的值,就能知道传参个数,所以可以通过for
循环来打印输入的参数;需要注意的是在命令行参数之前还有.*.exe
程序路径
#include <stdio.h>
//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;
}
输出结果
E:\VisualStudioProjects\StudyCProject\Debug\StudyCProject.exe
hello
123456
我们可以通过gcc
命令编译生成exe
可执行程序来执行命令行参数的打印
#include <stdio.h>
// 形参名随便取
int main(int n, char *v[]){
for(int i = 0; i < n; i++)
{
printf("%s\n", v[i]);
}
return 0;
}
PS C:\Users\Administrator\Desktop> gcc hello.c -o hello
PS C:\Users\Administrator\Desktop> ./hello.exe hello CSDN cdtaogang good good study
7) 字符串处理函数
7.1 strcpy()
拷贝字符串:
- 表头文件:
#include <string.h>
- 定义函数:
char *strcpy(char *dest, const char *src);
- 功能:把
src
所指向的字符串复制到dest
所指向的空间中,'\0'
也会拷贝过去 - 参数:
dest:
目的字符串首地址
src:
源字符首地址 - 返回值:
成功:返回dest
字符串的首地址
失败:NULL
注意:如果参数dest所指的内存空间不够大,可能会造成缓冲溢出的错误情况。
示例1:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
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;
}
输出结果
cdtaogang
hello
csdn
7.2 strncpy()
拷贝字符串:
- 表头文件:
#include <string.h>
- 定义函数:
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 <stdio.h>
#include <string.h>
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;
}
输出结果
str1=he
str1=hello
str1=he
104 101 0 0 0
7.3 strcat()
连接两字符串:
- 表头文件:
#include <string.h>
- 定义函数:
char *strcat(char *dest, const char *src);
- 功能:将
src
字符串连接到dest
的尾部,‘\0’
也会追加过去 - 参数:
dest:
目的字符串首地址
src:
源字符首地址 - 返回值:
成功:返回dest
字符串的首地址
失败:NULL
示例1:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
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;
}
输出结果
str1=hellocdtaogang
str1=hellocdtaogangworld
7.4 strncat()
连接两字符串:
- 表头文件:
#include <string.h>
- 定义函数:
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 <stdio.h>
#include <string.h>
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;
}
输出结果
str1=hello123
str1=hello123world
7.5 strcmp()
比较字符串:
- 表头文件:
#include <string.h>
- 定义函数:
int strcmp(const char *s1, const char *s2);
- 功能:比较
s1
和s2
的大小,比较的是字符ASCII
码大小。 - 参数:
s1:
字符串1首地址
s2:
字符串2首地址 - 返回值:
相等:0
大于:>0
在不同操作系统strcmp
结果会不同 返回ASCII
差值
小于:<0
示例1:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
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<str2\n");
}
return 0;
}
输出结果
strcmp(str1, str2):1
strcmp(str2, str3):0
strcmp(str2, str4):-1
str1>str2
7.6 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
示例1:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
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<str2\n");
}
return 0;
}
输出结果
strncmp(str1, str2, 7):1
strncmp(str2, str3, 6):0
strncmp(str2, str4, 1):-1
str1>str2
7.7 sprintf()
格式化字符串复制(组包函数)
- 表头文件:
#include <stdio.h>
- 定义函数:
int sprintf(char *str, const char *format, ...);
- 功能:根据参数
format
字符串来转换并格式化数据,然后将结果输出到str
指定的空间中,直到出现字符串结束符'\0'
为止。 - 参数:
str:
字符串首地址
format:
字符串格式,用法和printf()
一样 - 返回值:
成功:实际格式化的字符个数
失败:-1
示例1:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
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;
}
输出结果
buf=[today is 2022-11-19
]
2
len=21
7.8 sscanf()
格式化字符串输入(拆包函数)
- 表头文件:
#include <stdio.h>
- 定义函数:
int sscanf(const char *str, const char *format, ...);
- 功能:从
str
指定的字符串读取数据,并根据参数format
字符串来转换并格式化数据。 - 参数:
str:
指定的字符串首地址
format:
字符串格式,用法和scanf()
一样 - 返回值:
成功:参数数目,成功转换的值的个数
失败:-1
示例1:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
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;
}
输出结果
today is 2022-11-19
7.9 strchr()
查找字符串中第一个出现的指定字符
- 表头文件:
#include <string.h>
- 定义函数:
char *strchr(const char *s, int c);
- 功能:在字符串
s
中查找字母c
出现的位置 - 参数:
s:
字符串首地址
c:
匹配字母(字符) - 返回值:
成功:返回第一次出现的c
地址
失败:NULL
示例1:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
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;
}
示例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;
}
示例3:
int main() {
// strchr函数
char src[] = "ddda123abcd";
char* p = strchr(src, 'a');
printf("p = %s\n", p);
return 0;
}
7.10 strstr()
在一字符串中查找指定的字符串
- 表头文件:
#include <string.h>
- 定义函数:
char *strstr(const char *haystack, const char *needle);
- 功能:在字符串
haystack
中查找字符串needle
出现的位置 - 参数:
haystack:
源字符串首地址
needle:
匹配字符串首地址 - 返回值:
成功:返回第一次出现的needle
地址
失败:NULL
示例1:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
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;
}
示例2:
int main() {
// strstr函数
char str1[] = "ddddabcd123abcd333abcd";
char str2[] = "abcd";
char* p = strstr(str1, str2);
printf("p = %s\n", p);
return 0;
}
输出结果
p = abcd123abcd333abcd
7.11 strtok()
分割字符串
- 表头文件:
#include <string.h>
- 定义函数:
char *strtok(char *str, const char *delim);
- 功能:来将字符串分割成一个个片段。当
strtok()
在参数s
的字符串中发现参数delim
中包含的分割字符时, 则会将该字符改为\0
字符,当连续出现多个时只替换第一个为\0
。 - 参数:
str:
指向欲分割的字符串
delim:
为分割字符串中包含的所有字符 - 返回值:
成功:分割后字符串首地址
失败:NULL
示例1:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
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;
}
示例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;
}
示例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;
}
示例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;
}
7.12 atoi()
将字符串转换为整型数
- 表头文件:
#include <stdlib.h>
- 定义函数:
int atoi(const char *nptr);
- 功能:
atoi()
会扫描nptr
字符串,跳过前面的空格字符,直到遇到数字或正负号才开始做转换,而遇到非数字或字符串结束符('\0')
才结束转换,并将结果返回返回值。 - 参数:
nptr:
待转换的字符串 - 返回值:成功转换后整数
类似的函数有:
atof():
把一个小数形式的字符串转化为一个浮点数。atol():
将一个字符串转化为long
类型
示例1:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
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;
}
输出结果
a=1234
b=-1234
c=0
d=1234
e=3.140000
f=11321321
8) 项目开发常用字符串应用模型
8.1 strstr中的while和do-while模型
利用strstr
标准库函数找出一个字符串中abcd
出现的次数。
while模型
#include <stdio.h>
#include <string.h>
int main() {
char* p = "32e23abcd11132122abcd333abcd9922abcd333abc32d2qqq";
int n = 0;
// 查找匹配到到则进去,循环条件第一次从字符串首元素地址开始查找
while ((p=strstr(p, "abcd"))!=NULL)
{
// 进入循环后,说明此时已经匹配到一个了,那么就要重新设置查找起点位置
p += strlen("abcd");
n++;
}
printf("n=%d", n);
return 0;
}
输出结果
n=4
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;
}
输出结果
n=4
8.2 两头堵模型
求非空字符串元素的个数:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
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;
}
输出结果
15
buf=hello cdtaogang
8.3 字符串反转模型(逆置)
#include <stdio.h>
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;
}
指针小结
定义 | 说明 |
---|---|
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的一级指针) |