代码编织梦想

字符串函数(下列头文件均为“string.h”)

1.strlen (求字符串长度)

原型

在这里插入图片描述

  • 字符串计数不需修改字符串,因此用conut修饰;

模拟实现

#include<stdio.h>
#include<Windows.h>
#include<assert.h>
#pragma warning(disable:4996)

//方法1:计数器法--需要单独设置一个变量
size_t myStrlen1(const char *arr)  //字符串不需修改字符串,因此用conut修饰
//size_t在vs2013指无符号整型unsigned int
{
	assert(arr); //assert函数用来判断字符串是否不为空

	int count = 0;
	while (*arr)
	{
		count++;
		arr++;
	}
	return count;
}

//方法2:递归法--不创建临时变量
size_t myStrlen2(const char *arr)
{
	assert(arr);

	if (*arr == '\0')
	{
		return 0;
	}
	else
	{
		return 1 + myStrlen2(arr + 1);
	}
}

//方法3:指针法--利用尾指针-头指针获得长度
size_t myStrlen3(const char *arr)
{
	assert(arr); 

	char *p = arr;
	while (*p != '\0')
	{
		p++;
	}
	return p - arr;
}

int main()
{
	const char *arr = "abcd1234";
	int len1 = myStrlen1(arr);
	printf("方法1字符串arr长度为:%d\n", len1);
	int len2 = myStrlen2(arr);
	printf("方法2字符串arr长度为:%d\n", len1);
	int len3 = myStrlen3(arr);
	printf("方法3字符串arr长度为:%d\n", len1);

	system("pause");
	return 0;
}

2.strcpy (字符串拷贝)

原型

在这里插入图片描述

  • 将后面的参数拷贝到前面的参数,无需修改后者,因此后面参数用const修饰;
  • 注意后面的字符串参数大小不能大于前者,否则会报错;
  • 该函数返回值为char *类型,这是为了支持该类库函数的链式调用

模拟实现

#include<stdio.h>
#include<Windows.h>
#include<assert.h>
#pragma warning(disable:4996)

//编程习惯之-变量名:ret->result(结果);src->source(源数据);dest->destination(目标)

char *myStrcpy(char *dest, const char *src)
{
	assert(src);  assert函数用来判断字符串是否不为空
	assert(dest);

	char * ret = dest;
	while ((*dest++ = *src++));
	return ret;
}

int main()
{
	const char *src = "abcd";
	char dest[30] = { "12345" };
	printf("before:%s\n",dest);
	printf("after:%s\n", myStrcpy(dest, src));

	system("pause");
	return 0;
}

3.strcat(字符串拼接)

原型

011

  • 将后面的参数拼接到前面的参数,无需修改后者,因此后面参数用const修饰;
  • 前者字符串空间须足够大以容纳拼接后字符串;
  • 注意不能进行自我拼接(这样拼接时会出现原始串不断增加的情况);
  • 该函数返回值为char *类型,这是为了支持该类库函数的链式调用

模拟实现

#include<stdio.h>
#include<Windows.h>
#include<assert.h>
#pragma warning(disable:4996)

char *myStrcpy(char *dest, const char *src)
{
	assert(src);
	assert(dest);

	char * ret = dest;
	while (*dest) //将指针指向dest字符串尾部
	{
		dest++;
	}
	while ((*dest++ = *src++)); //从尾部开始将后者字符串拼接
	return ret;
}

int main()
{
	const char *src = "abcd";
	char dest[30] = { "12345" };
	printf("before:%s\n", dest);
	printf("after:%s\n", myStrcpy(dest, src));

	system("pause");
	return 0;
}

4.strcmp(字符串比较)

原型

  • 两字符串进行大小比较,无需修改字符串,因此两参数用const修饰;
  • 字符串比较是通过两字符串第一个不同的字符的ASSIC码值来判断;
  • 若str1>str2,返回1;若str1=str2,返回0;若str1<str2,返回-1;

模拟实现

#include<stdio.h>
#include<Windows.h>
#include<assert.h>
#pragma warning(disable:4996)

int myStrcmp(const char *str1, const char *str2)
{
	int ret = 0;
	assert(str1);
	assert(str2);

	//两字符串指针相减,若相同则看下一个字符,直到出现大小不同的字符或'\0'。
	while (!(ret = *(unsigned char *)str1 - *(unsigned char *)str2) && *str2)  
	{
		++str1, ++str2;
	}
	if (ret < 0)
	{
		ret = -1;
	}
	else if (ret>0)
	{
		ret = 1;
	}
	return (ret);
}

int main()
{
	const char *str1 = "abcd4";
	const char *str2 = "abcd5";

	int comp = myStrcmp(str1, str2);
	if (comp > 0)
	{
		printf("str1>str2\n");
	}
	else if (comp < 0)
	{
		printf("str1<str2\n");
	}
	else
	{
		printf("str1=str2\n");
	}

	system("pause");
	return 0;
}

5.strncpy(长度受限字符串拷贝)

原型

在这里插入图片描述

  • “安全拷贝”函数,即相比strcpy函数来说,参数增加了需要拷贝后者字符串的长度参数
  • 拷贝后不会自带’\0’,需要自己加;

6.strncat(长度受限字符串拼接)

原型

在这里插入图片描述

  • “安全拼接”函数,相比strcat函数来说,参数增加了需要拼接后者字符串的长度参数
  • 默认会在拼接后的字符串加’\0’

7.strncmp(长度受限字符串比较)

原型

在这里插入图片描述

  • “安全比较”函数,比较两字符串的前num个字符
  • 运算规则同strcmp;

8.strstr(字符串子串查找)

原型

在这里插入图片描述

  • 该函数能返回str1里第一次出现str2函数的第一个字符地址

应用

  • 替换一段字符串的某一个字串
  • 通过while循环实现查找一段字符串中某字符串出现的位置即次数;
    (以下为两个strtr的应用举例)
//strstr example_1 替换
//将一个长字符串的一个小字符串替换
int main()
{
	char str[] = "This is a simple string.";
	char *pch;
	pch = strstr(str, "simple");
	strncpy(pch, "sample", 6);
	puts(str);

	system("pause");
	return 0;
}

在这里插入图片描述

//strstr example_2 查找
//从一个长字符串找到小字符串的具体位置
int main()
{
	const char *s1 = "abcd1234worldABCD-1world,nkworld.";
	const char *s2 = "world";

	const char *s = s1;
	int count = 0;
	char *sub_str = NULL;
	while (1)
	{
		sub_str = strstr(s, s2);
		if (sub_str == NULL)
		{
			break;
		}
		count++;
		//sub_str = strcpy(sub_str, s2);
		printf("第%d个%s的位置:%d\n", count, s2, sub_str - s1);
		s = sub_str + 1;
	}

	system("pause");
	return 0;
}

在这里插入图片描述

模拟实现

char *myStrstr(const char*str1, const char *str2)
{
	assert(str1);
	assert(str2);

	char* str_p = (char*)str1;
	char* str_q = (char*)str2;

	char* judge_p = str_p; //外部循环瞄点

	if (*str2 == '\0')
	{
		return NULL;
	}
	while (*judge_p!='\0')
	{
		const char* move_p = judge_p ; //内部循环str1比较指针
		char* judge_q = str_q; //内部循环str2比较指针
		while (*move_p && *judge_q && *move_p == *judge_q)
		{
			move_p++;
			judge_q++;
		}
		if (*judge_q == '\0')
		{
			return judge_p;
		}
		judge_p++;
	}
	return NULL;
}

int main()
{
	const char *s1 = "abcd1234world5678";
	const char *s2 = "world";

	char *s = myStrstr(s1, s2);
	printf("before:%s\n", s1);
	printf("after:%s\n", s);

	system("pause");
	return 0;
}

在这里插入图片描述


9.strtok(字符串分割)

原型

在这里插入图片描述

  • 分割字符串函数:遍历参数一所指向的字符串,遇到参数二所包含的分割字符后即返回对应字符串首指针
  • 第二个参数可存放多个分割字符,比如:",._ "(双引号内的字符都是,包括空格);
  • 一次使用只能返回一个分割字串,因为只有一个返回值;
  • 即如果要多次对一个字符串使用该函数,第一次使用后下一次传参只能将参数一设为NULL,否则将清空记录,从新对该字符串起始位置遍历;
  • strtok库函数内部有static变量保存原字符串地址作为静态全局变量,当分割一个后,自动移向第一个分隔符后一个地址;
  • 分割字符串本质是将原字符串的对应分隔字符转为’\0’
  • 【注意】由上个条例可知该库函数会修改参数一,故参数一所指向的字符串不能定义在字符常量区

应用

  • 通过多次引用该函数将一个长字符串分割为多个小字符串;
  • 注意:由上面的特性4,5可知,重复调用函数以分割多个子字符串时,第一个参数不用变;
//strtok example_1
//将一个长字符串分割为多个小字符串

int main()
{
	char s1[] = "You are so beautiful,but not belong to me.";
	char *s = strtok(s1, ", .");
	while (s != NULL)
	{
		printf("%s\n", s);
		s = strtok(NULL, ", .");
	}

	system("pause");
	return 0;
}

在这里插入图片描述


10.strerror(错误报告

原型

在这里插入图片描述

  • 通过错误码返回错误信息
  • 错误码的理解:Eg:return 0;中的0就是main函数返回的一个“错误码”,一般0代表success;
  • 错误码的存在方便计算机,错误信息方便程序员;计算机擅长处理数字但不擅长处理字符串,与人相反;
  • C语言系统全局变量 errno ,在使用C库函数出错时,会自动设置相应错误信息的错误码;

应用

#include<stdio.h>
#include<Windows.h>
#include<string.h>
#include<errno.h>
#pragma warning(disable:4996)

//strerror example
//通过打开错误文件了解错误信息与错误码
//使用系统全局变量errno必须加头文件<errno.h>
int main()
{
	printf("before errno:%d\n", errno); //输出errno原始内容
	FILE * pf = NULL;
	pf = fopen("test.text", "r");
	if (pf == NULL)
	{
		printf("after errno:%d\n", errno); //输出errno遇到错误后自动修改的内容
		printf("ERROR Opening file test.text:%s\n", strerror(errno));
	}

	system("pause");
	return 0;
}

在这里插入图片描述


字符分类函数

字符分类函数函数(若其参数符合下列条件就返回真) 头文件:<ctype.h>
iscntrl :任何控制字符
isspace :空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’
isdigit :十进制数字 0~9
isxdigit :十六进制数字,包括所有十进制数字,小写字母af,大写字母AF
islower :小写字母a~z
isupper :大写字母A~Z
isalpha :字母az或AZ
isalnum :字母或者数字,az,AZ,0~9
ispunct :标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph :任何图形字符
isprint :任何可打印字符,包括图形字符和空白字符


内存操作函数(下列头文件均为“string.h”)

  • mem系列库函数的操作基本单位是字节
  • 参数类型为void *表明可以对任何类型进行该操作

1.memcpy(按字节内存拷贝)

原型

在这里插入图片描述

  • 不能进行自我拷贝,这也是与memmove的区别所在;(但现在的编辑器已支持,意味着两函数没有区别

模拟实现+特殊应用

#include<stdio.h>
#include<Windows.h>
#include<string.h>
#include<assert.h>
#pragma warning(disable:4996)
//模拟实现memcpy
//test2与test3为特殊应用
void* myMemcpy(void* dest, const void* src, size_t len)
{
	void* ret = dest;
	assert(dest);
	assert(src);

	while (len--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

int main()
{
	const char* src = "abcd";
	char dest[30] = { "12345" };
	//test1.普通测试
	printf("before:%s\n", dest);
	printf("after:%s\n", (char*)myMemcpy(dest, src, strlen(src)));
	//test2.正向自我拷贝:
	myMemcpy(dest, dest + 1, (strlen(dest) - 1));
	printf("正向自我拷贝:%s\n", dest);
	//test3.逆向自我拷贝
	myMemcpy(dest + 1, dest, (strlen(dest) - 1));
	printf("逆向自我拷贝:%s\n", dest);

	system("pause");
	return 0;
}

在这里插入图片描述

  • 逆向拷贝的错误体现了其不能自我拷贝
  • 具体原因:出现内存重叠,该函数一边拷贝一边将拷贝后的数据当作新数据拷贝给下一个;

2.memmove( 可按字节拷贝两个重叠内存)

原型

在这里插入图片描述

模拟实现+特殊应用

#include<stdio.h>
#include<Windows.h>
#include<string.h>
#include<assert.h>
#pragma warning(disable:4996)
//模拟实现memmove
//test2与test3为特殊应用
void* myMemmove(void* dest, const void* src, size_t len)
{
	void* ret = dest;
	assert(dest);
	assert(src);
	char* p = (char*)dest;
	char* q = (char*)src;

	if (p > q && p < q + len)  //逆向自我赋值情况,特殊处理
	{
		//从尾部赋值即可 从右向左
		p += (len-1);
		q += (len-1);
		while (len--)
		{
			*p = *q;
			p--;
			q--;
		}
	}
	else
	{
		//从左向右
		while (len--)
		{
			*p = *q;
			p++;
			q++;
		}
	}
	return ret;
}

int main()
{
	const char* src = "abcd";
	char dest[30] = { "12345" };
	//test1.普通测试
	printf("before:%s\n", dest);
	printf("after:%s\n", (char*)myMemmove(dest, src, strlen(src)));
	//test2.正向自我拷贝:
	myMemmove(dest, dest + 1, (strlen(dest) - 1));
	printf("正向自我拷贝:%s\n", dest);
	//test3.逆向自我拷贝
	myMemmove(dest + 1, dest, (strlen(dest) - 1));
	printf("逆向自我拷贝:%s\n", dest);

	system("pause");
	return 0;
}

在这里插入图片描述

  • 逆向拷贝未出错,与memcpy函数差异既体现于此;
  • 对于库函数来说,方法更复杂也更完善,现如今两函数无差别

3.memset(按字节内存赋值)

原型

在这里插入图片描述

  • 功能:将ptr所指向的地址逐字节将num个字节初始化为value
  • size_t为无符号整数类型简写;

应用

#include<stdio.h>
#include<Windows.h>
#include<string.h>
#pragma warning(disable:4996)

//memset可以使数组的初始化不用循环
int main()
{
	int a[5];
	memset(a, 0, sizeof(a)); //注意不是sizeof(a) / sizeof(a[0])
	int b[5];
	memset(b, 1, sizeof(b)); //按字节初始化 故赋值1不会达到预期
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
	for (int j = 0; j < 5; j++)
	{
		printf("%d ", b[j]);
	}
	printf("\n");

	system("pause");
	return 0;
}

在这里插入图片描述


4.memcmp(比较内存内容大小)

原型

在这里插入图片描述

  • 比较时严格按照ASCII码处理,包括数字类型;
  • 可以比较ASCII任何字符,而strcmp只能比较字符;
  • 若ptr1>ptr2,返回1;若ptr1=ptr2,返回0;若ptr1<ptr2,返回-1;
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Sober_harmonic/article/details/121036996

assert 的学习-爱代码爱编程

从JDK1.4版本开始,Java语言引入了断言(assert)机制。该类在package org.springframework.util包下。 目的:程序调试 测试代码或者调试程序时,总会做出一些假设,断言就是用于在代码中捕捉这些假设 当要判断一个方法传入的参数时,我们就可以使用断言。 例如: public Order creat

字符串处理函数&函数调用_chz-njit的博客-爱代码爱编程

字符串处理函数,编码时需增加预处理 “ #include<string.h> ” strcat 、strcpy(strncpy)、strcmp(strncmp) #include<stdio.h> #include<string.h> int main() { char str[20] = "hello"

c中模拟实现各种常用字符串函数_charles·的博客-爱代码爱编程

#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <assert.h> size_t my_strlen(const ch

golang_字符串操作: strings包中contains,join,index,repeat,split,trim,fields的用法介绍_grayan的博客-爱代码爱编程_strings.repeat

字符串处理 Contains func Contains(s, substr string) bool 判断字符串s是否包含子串substr。 fmt.Println(strings.Contains("seafoo

assert(断言)-爱代码爱编程

主要用于测试,达不到预期时抛出错误: assert(value[, message]);  参数说明:assert( 表达式, "错误时的提示" );说明:表达式返回true,即达预期 var assert = require('assert'); function add (a, b) { return a + b; } var expect

Java基础—assert断言(一)-爱代码爱编程

整理自:java基础之断言细谈(比较清楚和全面,可先看这个博客!!!)java assert断言的用法java断言机制Java断言机制java断言机制(assert) Java核心技术 卷I断言与异常(Assertion Vs Exception)(区别断言和异常的使用场景!!!) !另附JUnit中Assert简单介绍 一、何为断言 断言机制:允许j

对Java assert的理解-爱代码爱编程

断言(Assertion)是一种调试程序的方式。在Java中,使用assert关键字来实现断言。 断言是一种调试方式,断言失败会抛出AssertionError,只能在开发和测试阶段启用断言; 对可恢复的错误不能使用断言,而应该抛出异常; 断言很少被使用,更好的方法是编写单元测试。   我们先看一个例子: public static void

2020/9/11-TypeScript 学习记录002-爱代码爱编程

函数 具名函数 function get(name:string):string{ return name } 匿名函数 const get= function(name:string):string{ return name } //箭头函数 const get = (name:string):string =>

【Python】assert(断言)的使用-爱代码爱编程

本文旨在对于个人知识的梳理以及知识的分享,如果有不足的地方,欢迎大家在评论区指出 什么是assert断言 在测试样例中,执行完测试样例之后,最后一步要判断是pass还是fail,自动化测试脚本中一般吧这种生成测试结果的方法称为断言 如何使用assert断言 简易Demo# 首先assert后面需要跟布尔类型的值 if __name__ == "_

C语言——字符串旋转问题-爱代码爱编程

字符串的旋转: ABCD左旋一个字符为BCDA ABCD左旋两个字符为CDAB ABCD右旋一个字符为DABC ABCD右旋两个字符为CDAB 这里只写了左旋,右旋的原理和左旋一样。 目录 实现旋转字符串: 1、暴力求解法:  2、三步翻转法 判断一个字符串是否由另一个字符串旋转而来 1、暴力求解法: 2、优化算法: 关于用到的函数扩展

字符和字符串库函数及其模拟(strlen,strcpy,strcat,strstr,strncat,strncmp,strncpy,atoi,memmove等库函数模拟实现)-爱代码爱编程

一、字符和字符串操作函数 strlen 求字符串长度定义 strlen返回值为size_t即无符号整型。长度不包括’\0’。使用 程序: #include<stdio.h> #include<Windows.h> #include<string.h> int main() { const char* str1

python提取图片经纬度并锁定拍照地点-爱代码爱编程

系列文章目录 文章目录 系列文章目录前言一、原理1.图片必须具有经纬度信息2.经纬度格式转换2.1 GPS点坐标的两种表示方式(误差还是有的)2.1.1 十进制换度分秒2.1.2 度分秒换十进制2.1.3 实际距离换算3.根据经纬度定位二、python调用高德API进行图片定位1.main.py源码2.position_utils.py源码总结