C语言-基础

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码
字符 ‘048
字符 ‘049

字符 ‘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;
}

后记

功夫不负有心人,希望这篇笔记对有需要的人,有一定参考价值,后续还会更新,内存管理、符合类型(自定义类型)、文件操作。持续更新中。

  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值