C语言在命令行下编译代码:
gcc工作流程
# 创建并编辑hello.c文件
wjg@wjg:~$ vim hello.c
# 查看hello.c文件是否创建好
wjg@wjg:~$ ls hello.c
hello.c
# 第一步:进行预处理
wjg@wjg:~$ gcc -E hello.c -o hello.i
# 第二步:生成汇编文件
wjg@wjg:~$ gcc -S hello.i -o hello.s
# 第三步:生成目标代码
wjg@wjg:~$ gcc -c hello.s -o hello.o
# 第四步:生成可执行文件
wjg@wjg:~$ gcc hello.c -o hello
# 第五步:执行
wjg@wjg:~$ ./hello
hello,xiaowang
- 常用: 直接将源文件生成一个可以执行文件
//gcc、g++编译常用选项
-o 指定生成的输出文件名为file
-E 只进行预处理
-S 只进行预处理和编译
-c 只进行预处理、编译和汇编
//代码这样写
//在自己的电脑上配置了gcc、g++的环境后,打开cmd,切换到自己已经写好的程序的目录下输入以下代码,以hello.c为例:
第一步:gcc hello.c -o hello
第二步:hello.exe
注意:-o后面没写文件名的话,默认生成a.exe
system 库函数
作用:在程序中启动另一个程序
参数:要的是待启动程序的路径名
#include <stdio.h>
#include<stdlib.h>
int main() {
//system("mspaint");//启动画图板
//window路径以\\或/
system("D:/C++/C完整/01_helloworld/01_helloworld/world.exe");
printf("使用了system库函数\n");
return 0;
}
寄存器、缓存、CPU、内存之间的关系
执行速度排序:
cpu > 寄存器 > 缓存 > 内存
vs中C语言嵌套汇编
#include <stdio.h>
int main() {
int a, b, c;
_asm
{
mov a,3 //3的值放在a对应的内存位置
mov b,4 //4的值放在a对应的内存位置
mov eax,a //把a内存的值放在eax寄存器
add eax,b //eax和b相加,结果放在eax
mov c,eax //eax的值放在c中
}
printf("%d\n", c);
return 0;
}
注意:vs编译环境仅支持X86的X64的不支持
VS中出现4996警告编号
只需要在文件的最前面加上一句话:
两者其一
//这个宏定义最好要放到.c文件的第一行
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)
数据类型
//进制的书写和打印
#include <stdio.h>
int main() {
int b = 056;
int c = 123;
int d = 0xab;
printf("a=%X\n", d);
printf("a=%o\n", b);
printf("a=%d\n", c);
printf("a=%#X\n", d);
return 0;
}
//整数的输入
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
int num;
printf("输入整数:\n");
scanf("%d", &num);
printf("num=%d", num);
return 0;
}
字符的ASCII码
字符 ‘0’ 48
字符 ‘0’ 49
字符 ‘A’ 65
字符 ‘B’ 48
字符 ‘a’ 97
字符 ‘b’ 98
知识点:因为字符所对应的最大ASCII值是127,所以用char类型就可以存的下所有的字符
//字符的输入
//从键盘读取一个字符
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
char ch = 0;
printf("输入一个字符:\n");
scanf("%c", &ch);
printf("ch=%c\n", ch);
return 0;
}
//浮点型数据输出
#include <stdio.h>
int main() {
double a = 3.14159264;
float b = 3.1415964;
printf("a=%.8f\n", a);
printf("b=%.8lf\n", b);
return 0;
}
sizeof
sizeof用来测数据类型的大小
限定符
extern 声明,(告诉编译器有这个东西,不开辟空间)
const 修饰的内容不可改变
volatile 防止编译器优化
Register 建议将变量定义在寄存器中
scanf和getchar函数的比较
作用:都是从键盘读取一个字符
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
char ch = 0;
printf("输入一个字符:\n");
ch = getchar();
printf("ch=%c\n", ch);
return 0;
}
运算符与程序结构(有基础,过一遍)
算术运算符:+、-、*、/、%
自加自增:++、–
赋值运算符:=、+=、-=、*=、/=、%=
比较运算符:==、!=、>、<、<=、>=
逻辑运算符:||、&&、!
逗号运算符:,
三目运算符:?···· : ······
类型转换:(需要转换的类型)带转换的类型
强制转换宗旨:数据不丢失,为了保证数据不丢失一般都是小的转大的
程序结构
//选择结构
if{}
if{}
else{}
if{}
else if{}
else{}
//分支语句
switch(){
case 0:
break;
case 1:
break;
case ...:
break;
default:
break;
}
//循环结构
while(){
代码块;
}
do{
代码块;
}while();
for(A;B;C){
代码块;
}
break、continue、goto
break:跳出switch或者离break最近的循环
continue:结束本次循环
goto:无条件跳转
数组(有基础)
//数组定义
int num[10];
//数组定义初始化
int num[10] = {1,2,3,4,5,6,7,8,9,10};
//求数组的个数
sizeof(num)/sizeof(num[0]);
函数(有基础,略过)
main函数与exit函数
- 在main函数中调用exit和return结果是一样的,但在子函数中调用return知识代表子函数终止了,在子函数中调用exit,那么程序终止。
多文件(分文件编写)
- 把函数声明放在头文件xxx.h中,在主函数中包含相应头文件
- 在头文件对应的xxx.c中实现xxx.h声明的函数
防止头文件重复包含
- 当一个项目比较大时,往往都是分文件,这时候有可能不小心把同一个头文件 include 多次,或者头文件嵌套包含。
- 为了避免同一个文件被include多次,C/C++中有两种方式,一种是 #ifndef 方式,一种是 #pragma once 方式。
// 方法1:
#ifndef _SOMEFILE_H_
#define _SOMEFILE_H_
// 声明语句
#endif
// 方法2:
#pragma once
// 声明语句
指针
指针变量:存放指针(地址)的变量
指针变量的定义和初始化
int a = 10;
int* p = &a
//指针变量保存谁的地址就指向谁
*p = 100; //在使用时,*与p结合代表,取指针所指向那块空间的内容
//打印指针(地址)
printf("地址是:%p\n",p);
printf("地址是:%p\n", &a);
指针大小
#include <stdio.h>
int main() {
//使用sizeof()测量指针的大小,得到的总是:4或8
//sizeof()测的是指针变量指向的存储地址的大小
//在32位平台,所有的指针(地址)都是32位(4个字节)
//在64位平台,所有的指针(地址)都是64位(8个字节)
char* p1;
short* p2;
int* p3;
double* p4;
float* p5;
printf("%d\n", sizeof(p1));
printf("%d\n", sizeof(p2));
printf("%d\n", sizeof(p3));
printf("%d\n", sizeof(p4));
printf("%d\n", sizeof(p5));
return 0;
}
野指针
#include <stdio.h>
int main() {
//野指针就是没有初始化的指针,指针的指向是随机的,不可以操作野指针
int* p;//野指针
*p = 200;
printf("%d\n", *p);
return 0;
}
空指针
空指针的作用:如果使用完指针将指针赋值为NULL,在使用时判断一下指针是否为NULL,就知道指针有没有被使用
#include <stdio.h>
int main() {
int a;
int* p = NULL; //给指针p的内容赋值为0
*p = 200; //因为p保存了0x0000的地址,这个地址是不可以使用的,非法
printf("%d\n", *p);
return 0;
}
万能指针
万能指针就是可以保存任意的地址
#include <stdio.h>
int main() {
//void b;不可以定义void类型的变量,因为编译器不知道给变量分配多大的空间
//但是可以定义void* 类型,因为指针不是8字节就是4字节
int a = 10;
short b = 20;
//万能指针可以保存任意地址
void* p = (void*)&a;
void* q = (void*)&b;
//printf("%d\n", *p);//eer p是void*,不知道取几个字节的大小
printf("%d\n", *(int*)p); //int* p相当于是一个地址,再给地址加*号就是取地址里面的值,所以打印的是10
return 0;
}
const修饰的指针变量(int类型举例说明)
#include <stdio.h>
int main() {
int a = 200;
int b = 100;
//指向常量的指针
//修饰*,指针指向内存区域不能修改,指针指向可以改变
const int* p1= &a;//等价于int const* p1 = &a
//*p1 = 111;err
p1 = &b;
printf("%p\n", p1);
//指针常量
int* const p2 = &a;
//p2 = &b;//err
*p2 = 222;
printf("%d\n", *p2);
return 0;
}
温馨提示:在编辑程序时,指针作为函数参数,如果不想修改指针对应内存空间的值,需要使用const修饰指针数据类型。
指针和数组
数组名
数组名字是数组的首元素地址,它是一个常量
int a[] = {1,2,3,4,5};
printf("a=%p\n",a);
printf("&a[0]=%p\n",&a[0]);
//a=10;eer 数组名是一个常量,不能被修改
指针操作数组元素
#include <stdio.h>
int main() {
int a[] = { 1,2,3,4,5,6,7,8,9 };
int i = 0;
int n = sizeof(a) / sizeof(a[0]);
for (i = 0; i<n; i++) {
//printf("a[%d]=%d\n", i, a[i]);
printf("a[%d]=%d\n", i,*(a + i));
}
printf("-----------------------\n");
int* p = a;//定义一个指针变量保存a的地址
for (i = 0; i < n; i++) {
printf("a[%d]=%d\n", i,*(p+i)) ;
}
return 0;
}
指针加减运算
1.加法运算
指针计算不是简单的整数相加
如果是一个int*,+1的结果就是增加一个int的大小
如果是一个char*,+1的结果就是增加一个char的大小
int main() {
int a;
int* p1 = &a;
printf("p1=%p\n", p1);
p1 += 2;
printf("p1=%p\n",p1 += 2);
char b;
char* p2 = &b;
printf("p2=%p\n", p2);
p2 += 2;
printf("p2=%p\n", p2 += 2);
}
2.减法运算
int main() {
int a[] = { 1,2,3,4,5,6,7,8,9 };
int* p2 = &a[2];
int* p1 = &a[1];
printf("p1=%p\np2=%p\n", p1, p2);
int n1 = p2 - p1;
int n2 = (int)p2 - (int)p1; //两个指针相减,得到两个地址间元素个数 n1=1
printf("n1=%d\nn2=%d", n1, n2);//两个地址的值相减 n2=4
return 0;
}
指针数组
指针数组,它是数组,数组的每个元素都是指针类型
int main() {
int* p[3];
int a = 1;
int b = 2;
int c = 3;
int i = 0;
p[0] = &a;
p[1] = &b;
p[2] = &c;
//printf("%d\n", (int)p[0]);
for (i = 0; i < sizeof(p) / sizeof(p[0]); i++) {
printf("%d ", *(p[i]));
}
printf("\n");
return 0;
}
多级指针
1.C语言允许多级指针存在,在实际的程序中一级指针最常用,其次是二级指针
2.二级指针就是指向一个一级指针变量地址的指针
3.三级指针基本用不着,但是考试会考
int a = 10;
//一级指针
int* p = &a;
//*p就是a
//二级指针
int** q = &p;
//*q就是p,**q就是a
//三级指针
int*** t = &q;
//*t就是q,**t就是p,***t就是a
指针和函数
int a = 1;
int b = 2;
int c = 3;
int i = 0;
p[0] = &a;
p[1] = &b;
p[2] = &c;
//printf("%d\n", (int)p[0]);
for (i = 0; i < sizeof(p) / sizeof(p[0]); i++) {
printf("%d ", *(p[i]));
}
printf("\n");
return 0;
}
多级指针
1.C语言允许多级指针存在,在实际的程序中一级指针最常用,其次是二级指针
2.二级指针就是指向一个一级指针变量地址的指针
3.三级指针基本用不着,但是考试会考
int a = 10;
//一级指针
int* p = &a;
//*p就是a
//二级指针
int** q = &p;
//*q就是p,**q就是a
//三级指针
int*** t = &q;
//*t就是q,**t就是p,***t就是a
指针和函数
- 函数形参改变实参的值
#include <stdio.h>
void swap1(int x, int y)
{
int tmp;
tmp = x;
x = y;
y = tmp;
printf("值传递:\nx=%d,y=%d\n", x, y);
}
void swap2(int* x, int* y)
{
int tmp;
tmp = *x;
*x = *y;
*y = tmp;
printf("地址传递:\nx=%d,y=%d\n", *x, *y);
}
int main()
{
int a = 3, b = 5;
swap1(a, b); // 值传递
printf("a=%d,b=%d\n", a, b);
swap2(&a, &b); // 地址传递
printf("a=%d,b=%d\n", a, b);
return 0;
}
图片解释:
- 数组名作为函数参数
#include <stdio.h>
void printArray(int* a, int n)
{
int i = 0;
for (i = 0;i < n;i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
int main()
{
int a[] = { 1,2,3,4,5,6,7,8,9 };
int n = sizeof(a) / sizeof(a[0]);
// 数组名作为函数参数
printArray(a, n);
return 0;
}
- 指针作为函数的返回值
#include <stdio.h>
int a = 10;
// 指针作为函数的返回值
int* getA()
{
return &a;
}
int main()
{
// getA()函数返回的是a的地址,想要给其赋值需要用*解引用赋值
*(getA()) = 111;
printf("a=%d\n", a);
return 0;
}
指针和字符串
- 字符指针
#include <stdio.h>
int main()
{
char str[] = "hello world";
// 字符指针
char* p = str;
*p = 'm';
p++;
*p = 'i';
printf("%s\n", str);
p = "mike jiang";
printf("%s\n", p);
char* q = "test";
printf("%s\n", q);
}
- 字符指针做函数参数
// 字符指针做函数参数
// 拼接两个字符串,目标指针可以修改,保证源指针不修改
void mystrcat(char* dest, const char* src)
{
int len1 = 0;
int len2 = 0;
while (dest[len1])
{
len1++;
}
while (src[len2])
{
len2++;
}
for (int i = 0;i < len2;i++)
{
dest[len1 + i] = src[i];
}
}
int main()
{
char dst[100] = "hello jianguo";
char src[] = "123456";
mystrcat(dst, src);
printf("dst=%s\n", dst);
return 0;
}
- const修饰的指针变量(char字符数组举例说明)
#include <stdio.h>
int main()
{
// const修饰一个变量为只读
const int a = 10;
// a=100; err
// 指针变量,指针指向的内存,2个不同概念
char b[] = "abc";
char q[] = "hello";
/*
从左往右看,跳过类型,看修饰那个字符
- 如果是*,说明指针指向的内存不能改变,也就是指向可以改变,值不能修改
- 如果是指针变量,说明指针的指向不能改变,指针的指向的内存区域可以修改,即值能修改
*/
const char* p = b;
// 此种写法等价于上面的写法char const* p = b;
// p[1] = 2; err,指针的值不能修改
p = q; // ok,指针由原来的指向b,变为指向q,是可以的
char* const p1 = b;
p1[1] = '2'; // ok,指针的值可以修改
//p1 = q; err,修饰的是指针变量,所以指向不能改变
// p2为只读,指向不能变,指向的内存也不能变(即值不能变)
const char* const p2 = b;
/*
这两种写法都报错
p2 = q; 指针指向不能变
p2[1] = 'd'; 指针指向内存不能变
*/
return 0;
}
- 指针数组作为main函数的形参
int main(int argc,char* argv[])
mian函数是操作系统调用的,第一个参数标明argc数组的成员数量,argv数组的每个成员都是char* 类型
argv是命令行参数的字符串数组
argc代表命令行参数的数量,程序名字本身算一个参数
#include <stdio.h>
// argc:传参数的个数(包含可执行程序)
// argv:指针数组,指向输入参数
int main(int argc, char* argv[])
{
// 指针数组,它是数组,每个元素都是指针,下面的指针数组是对char* argv的解释
char* a[] = { "aaa","bbb","ccc" };
int i = 0;
printf("argc=%d\n", argc);
for (i = 0;i < argc;i++)
{
printf("%s\n", argv[i]);
}
return 0;
}
- 命令行图片参数解释及设置
- 在Visual Studio软件中,右键选择正在编辑的项目->属性->调试->命令行参数
运行结果及解释
字符串处理函数
1. strcpy(): 字符串拷贝
#include <string.h>
char *strcpy(char *dest,const char *src);
功能:把src所指向的字符串复制到dest所指向的空间中,'\0’也会拷贝过去
参数:
dest:目的字符串首地址
src:源字符串首地址
返回值:
成功:返回dest字符串首地址
失败:返回NULL
注意:如果dest所指的内存空间不够大,可能会造成缓冲溢出的错误情况
#include <stdio.h>
int main(void)
{
char dest[20] = "123456789";
char src[] = "hello world";
// 把src所指向的字符串复制到dest所指向的空间中,'\0'也会拷贝过去
strcpy(dest, src);
printf("%s\n", dest);
return 0;
}
2. strncpy(): 字符串拷贝
#include <string.h>
char *strncpy(char *dest, const char *src, size_t n);
功能:把src指向字符串的前n个字符复制到dest所指向的空间中,是否拷贝结束符看指定的长度是否包含’\0’。
参数:
dest:目的字符串首地址
src:源字符首地址
n:指定需要拷贝字符串个数
返回值:
成功:返回dest字符串的首地址
失败:NULL
#include <stdio.h>
int main(void)
{
char dest[20];
char src[] = "hello world";
strncpy(dest, src, 7);
dest[7] = '\0';
printf("%s\n", dest);
return 0;
}
3. strcat(): 字符串追加
#include <string.h>
char *strcat(char *dest, const char *src);
功能:将src字符串连接到dest的尾部,‘\0’也会追加过去
参数:
dest:目的字符串首地址
src:源字符首地址
返回值:
成功:返回dest字符串的首地址
失败:NULL
#pragma warning(disable:4996) //解决报4996警告问题
#include <stdio.h>
#include <string.h>
int main(void)
{
char dest[20] = "kkk ";
char* src = "hello world";
/*strcat(dest, src);*/
printf("%s\n", strcat(dest, src));
return 0;
}
4. strncat(): 字符串追加
#include <string.h>
char *strncat(char *dest, const char *src, size_t n);
功能:将src字符串前n个字符连接到dest的尾部,‘\0’也会追加过去
参数:
dest:目的字符串首地址
src:源字符首地址
n:指定需要追加字符串个数
返回值:
成功:返回dest字符串的首地址
失败:NULL
#pragma warning(disable:4996)
#include <stdio.h>
#include <string.h>
int main(void)
{
char dest[20] = "www.";
char* src = "hello world";
printf("%s\n", strncat(dest, src, 7));
return 0;
}
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
#pragma warning(disable:4996)
#include <stdio.h>
#include <string.h>
int main(void)
{
// s1和s2的字符逐个比较,如果ASCII码相同,继续向下比较
// 如果ASCII码不相同,在windows系统下大于返回1,小于返回-1
char s1[] = "hello db";
char s2[] = "hello ad";
if (strcmp(s1, s2) == 0)
{
printf("s1等于s2\n");
}
else if (strcmp(s1, s2) > 0)
{
printf("s1大于s2\n");
}
else
{
printf("s1小于s2\n");
}
return 0;
}
6. strncmp(): 字符串比较
#include <string.h>
int strcmp(const char *s1, const char *s2,size_t n);
功能:比较 s1 和 s2 的大小,比较的是字符ASCII码大小。
参数:
s1:字符串1首地址
s2:字符串2首地址
n:指定比较字符串的数量
返回值:
相等:0
大于:>0 在不同操作系统strcmp结果会不同 返回ASCII差值
小于:<0
#pragma warning(disable:4996)
#include <stdio.h>
#include <string.h>
int main(void)
{
// s1和s2的字符逐个比较,如果ASCII码相同,继续向下比较
// 如果ASCII码不相同,在windows系统下大于返回1,小于返回-1
char s1[] = "hello db";
char s2[] = "hello ad";
if (strncmp(s1, s2) == 0)
{
printf("s1等于s2\n");
}
else if (strncmp(s1, s2) > 0)
{
printf("s1大于s2\n");
}
else
{
printf("s1小于s2\n");
}
return 0;
}
注意:比较字符串是比较的ASCII码,不是比较的内容 |
7. sprintf(): 字符串按指定格式输出
#include <stdio.h>
int sprintf(char *str, const char *format, ...);
功能:根据参数format字符串来转换并格式化数据,然后将结果输出到str指定的空间中,直到出现字符串结束符'\0’为止。
参数:
str:字符串首地址
format:字符串格式,用法和printf()一样
返回值:
成功:实际格式化字符个数
失败:-1
#pragma warning(disable:4996)
#include <stdio.h>
#include <string.h>
int main(void)
{
char dst[100];
int a = 10;
char src[] = "hello world";
printf("a=%d,src=%s", a, src);
printf("\n");
int len = sprintf(dst, "a=%d,src=%s", a, src);
printf("dst=\"%s\"\n",dst);
printf("len=%d\n", len);
return 0;
}
8. sscanf(): 字符串按指定格式输入
#include <stdio.h>
int sscanf(const char *str, const char *format, ...);
功能:从str指定的字符串读取数据,并根据参数format字符串来转换并格式化数据。
参数:
str:指定的字符串首地址
format:字符串格式,用法和scanf()一样
返回值:
成功:参数数目,成功转换的值的个数
失败: - 1
#pragma warning(disable:4996)
#include <stdio.h>
#include <string.h>
int main()
{
char src[] = "a=10,b=20";
int a, b;
sscanf(src, "a=%d,b=%d", &a, &b);
printf("a:%d,b:%d\n", a, b);
return 0;
}
9. strchr(): 字符查找
#include <string.h>
char *strchr(const char *s, int c);
功能:在字符串s中查找字母c出现的位置
参数:
s:字符串首地址
c:匹配字母(字符)
返回值:
成功:返回第一次出现的c地址
失败:NULL
#pragma warning(disable:4996)
#include <stdio.h>
#include <string.h>
int main()
{
char src[] = "ddda123abcd";
char* p = strchr(src, 'a');
printf("p=%s\n", p);
return 0;
}
**10. strstr():**字符串查找
#include <string.h>
char *strstr(const char *haystack, const char *needle);
功能:在字符串haystack中查找字符串needle出现的位置
参数:
haystack:源字符串首地址
needle:匹配字符串首地址
返回值:
成功:返回第一次出现的needle地址
失败:NULL
#pragma warning(disable:4996)
#include <stdio.h>
#include <string.h>
int main()
{
char src[] = "123456abc456789abc";
char* p = strstr(src, "abc");
printf("p=%s", p);
return 0;
}
11. strtok(): 字符串分割
#include <string.h>
char *strtok(char *str, const char *delim);
功能:来将字符串分割成一个个片段。当strtok()在参数s的字符串中发现参数delim中包含的分割字符时, 则会将该字符改为\0 字符,当连续出现多个时只替换第一个为\0。
参数:
str:指向欲分割的字符串
delim:为分割字符串中包含的所有字符
返回值:
成功:分割后字符串首地址
失败:NULL
- 在第一次调用时:strtok()必需给予参数s字符串
- 往后的调用则将参数s设置成NULL,每次调用成功则返回指向被分割出片段的指针
#pragma warning(disable:4996)
#include <stdio.h>
#include <string.h>
int main()
{
char a[] = "abc*def*123*wjg";
// 将"*"分割的子串取出
char* s = strtok(a, "*");
while (s != NULL)
{
printf("%s\n", s);
s = strtok(NULL, "*");
}
return 0;
}
12. atoi(): 字符串转换为整型
#include <stdlib.h>
int atoi(const char *nptr);
功能:atoi()会扫描nptr字符串,跳过前面的空格字符,直到遇到数字或正负号才开始做转换,而遇到非数字或字符串结束符(‘\0’)才结束转换,并将结果返回返回值。
参数:
nptr:待转换的字符串
返回值:成功转换后整数
类似的函数有:
- atof():把一个小数形式的字符串转化为一个浮点数。
- atol():将一个字符串转化为long类型
#pragma warning(disable:4996)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char str1[] = "+10678sse";
int num1 = atoi(str1);
printf("num1 = %d\n", num1);
char str2[] = "0.123";
double num2 = atof(str2);
printf("num2 = %lf\n", num2);
return 0;
}
项目中开发常用字符串应用类型
1. strstr中的while和do-while模型
- 利用strstr标准库函数找出一个字符串中substr出现的个数
- while模型
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char* p = "123456abcd5647abcd7894abcd";
int n = 0;
while ((p = strstr(p, "abcd")) != NULL)
{
// 能进来,肯定有匹配的子串
// 重新设置起点位置,跳过abcd寻找下一个abcd
p = p + strlen("abcd");
n++;
if (*p == 0) // 如果到结束字符
{
break;
}
}
printf("%d\n", n);
return 0;
}
- do-while模型
#include <stdio.h>
#include <string.h>
int main()
{
char* p = "11abc22abc33abcqqabc";
int n = 0;
do
{
p = strstr(p, "abc");
if (p == NULL)
{
break;
}
else
{
n++;
p += strlen("abc");
}
} while (*p!=0);
printf("%d\n", n);
return 0;
}
- 两头堵模型
求非空字符串元素的个数:
#include <stdio.h>
#include <string.h>
int foo(char* p, int* n)
{
// 判断参数是否有效
if (p == NULL || n == NULL)
{
return -1;
}
// 两头堵的下标设置初始值
int begin = 0;
int end = strlen(p) - 1;
// 左边下标向右移动
while (p[begin] == ' ' && p[begin] != 0)
{
begin++;
}
// 右边下标向左移动
while (p[end] == ' ' && end > 0)
{
end--;
}
// 如果右边移动到最左边,说明全是空格
if (end == 0)
{
return -2;
}
// 计算非空格字符个数
*n = end - begin + 1;
// return 0 表示计算成功
return 0;
}
int main()
{
char* p = " abcdefghijkl ";
int ret = 0;
int n = 0;
ret = foo(p, &n);
// 非零表示数据有错
if (ret != 0)
{
return ret;
}
printf("非空格字符串的个数:%d\n", n);
return 0;
}
- 字符串反转模型(逆置)
#include <stdio.h>
#include <string.h>
int inverse(char* p)
{
if (p == NULL)
{
return -1;
}
char* str = p;
int begin = 0;
int end = strlen(p) - 1;
char tmp;
while (begin <= end)
{
// 交换元素
tmp = str[begin];
str[begin] = str[end];
str[end] = tmp;
// 向右移动位置
begin++;
// 向左移动位置
end--;
}
return 0;
}
int main()
{
//char *str = "abcdefg"; // 文件常量区,内容不允许修改
char str[] = "abcdefg";
int ret = inverse(str);
if (ret != 0)
{
return ret;
}
printf("str=========%s\n", str);
return 0;
}
后记
功夫不负有心人,希望这篇笔记对有需要的人,有一定参考价值,后续还会更新,内存管理、符合类型(自定义类型)、文件操作。持续更新中。