C/C++数据处理基本函数

Qt使用Printf打印调试信息

一、C/C++数据处理基本函数

1. atoi

字符串转换成整型数
atoi (表示 ascii to integer)是把字符串转换成整型数的一个函数,函数会扫描参数 nptr字符串,会跳过前面的空白字符(例如空格,tab缩进)等。
如果 nptr不能转换成 int 或者 nptr为空字符串,那么将返回 0 。特别注意,该函数要求被转换的字符串是按十进制数理解的。
atoi输入的字符串对应数字存在大小限制(与int类型大小有关),若其过大可能报错-1。

itoa是广泛使用的非标准C语言和C++语言扩展功能。但因为它是一个非标准的C / C++语言功能,因此不能好好的被所有编译器使用。
所以转化最好使用sprintf来转化。


#include <stdlib.h>
#include <stdio.h>
int atoi(const char *nptr);

int val1,val2;
const char* str1 = "12345";
val1 = atoi(str1);
printf("val1 = %d\n",val1);//12345

const char* str2 = "abc";
val2 = atoi(str2);

printf("val2 = %d\n",val2);//0

2. strtol

strtol函数会将参数nptr字符串根据参数base来转换成长整型数,参数base范围从2至36,或0。
一开始strtol()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,再遇到非数字或字符串结束时('\0')结束转换,并将转换数值返回。参数endptr指向停止转换的位置,若字符串nptr的所有字符都成功转换成数字则endptr指向串结束符'\0'。判断是否转换成功,应检查**endptr是否为'\0'。

#include<stdlib.h>
#include<stdio.h>
long int strtol(const char *nptr,char **endptr,int base);

const char* hex_str = "c9";
int hex_val = strtol(hex_str,NULL,16);
printf("hex_val = %x\n",hex_val);//c9

3. 数组数转化字符串

//转化字符串"hello"        
uint8_t t[6];
t[0]=0x68;
t[1]=0x65;
t[2]=0x6c;
t[3]=0x6c;
t[4]=0x6f;
t[5]='\0';
const char *str =(const char*)t;
qDebug()<<QString::fromStdString(str);

4. strlen

当计算长度时,只有遇到'\0'才会停止计算,同时计算的长度不包含'\0'。

#include<string.h>
size_t strlen(const char *s);
s:字符串首元的地址
返回值是:字符串的字符个数 不包含'\0'
注意:带str的函数都是遇到'\0'结束

char* str1  ="hello";
char  str2[]="hello";
printf("%d\r\n",strlen("hello")); //5
printf("str1:%d\r\n",strlen(str1));//5
printf("str2:%d\r\n",strlen(str2));//5

5. strcpy strncpy

字符串拷贝函数
strcpy
strcpy也是C++语言的一个标准函数 ,strcpy把含有'\0'结束符的字符串复制到另一个地址空间,返回值的类型为char*。
功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间。
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
返回指向dest的指针。

#include <stdio.h>
#include <string.h>
char *strcpy(char *dest, const char *src);
//将src指向的字符串 拷贝到 dest指向的空间中
返回值为:dest指向的地址

void test()
{
    char src[]="hello";
    char dst[128]=""; 
    strcpy(dst, src); 
    printf("%s\n", dst);//hello
}

数据组合


int8_t data[18];
data[0] = 0xFF;
data[1] = 0xF2;

uint8_t info[16];
strcpy((char*)info,"erlabsuperman");

for(int i =0;i<16;i++)
{
 data[i+2]=info[i];             
}

strncpy
char *strncpy(char *dest, const char *src, int n),表示把src所指向的字符串中以src地址开始的前n个字节复制到dest所指的数组中,并返回被复制后的dest。
结果dest不包括'\0',需要再手动添加一个'\0'。
strncpy()不会向dest追加结束标记’\0’,这就引发了很多不合常理的问题。
strncpy复制后dest如果最后一个没有’\0’,用dest的时候没有结束位置,后续对于字符串的操作可能会造成内存的非法访问。
如:printf("%s\n",dest);这句话可能就会输出一些不是你想要的结果。
char *strncpy(char *dest, const char *src, size_t n);
用的时候最后一位记得补 '\0'

char src[]="hello";
char dst[128]="";
strncpy(dst, src, 3);
dst[3]='\0';
printf("%s\n", dst);//hel
char src[]="hello";
char dst[128]="";
strncpy(dst, src+2, 3);
dst[3]='\0';
printf("%s\n", dst);//llo

6. memset

void *memset(void *s, int ch, size_t n);
函数解释:将 s 中当前位置后面的 n 个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。

注意点:
1.memset 函数按字节对内存块进行初始化,所以不能用它将int数组初始化为 0 和 -1 之外的其他值(除非该值高字节和低字节相同)。
2.memset(void *s, int ch,size_t n); 中ch实际范围应该在0~255,因为该函数只能取ch的后八位赋值给你所输入的范围的每个字节。

例如 把一个int数组值设置成3, memset(data,3,3*sizeof(int)); 整数是占内存四个字节长,四个字节一个字节一个字节设置成3。
也就是 0x03 0x03 0x03 0x03
0000 0011
0000 0011
0000 0011
0000 0011

int data[3];
data[0]=256;
data[1]=257;
data[2]=258;

memset(data,3,3*sizeof(int));

for(int i=0;i<3;i++)
{ 
   printf("i,data:%d,0x%2x\r\n",i,data[i]);
   /*
	i,data:0,0x3030303   0000 0011 0000 0011 0000 0011 0000 0011
	i,data:1,0x3030303
	i,data:2,0x3030303
   */
}


7. memcpy

void *memcpy(void *destin, void *source, unsigned n);
函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源source中拷贝n个字节到目标destin中。
参数
destin-- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
source-- 指向要复制的数据源,类型强制转换为 void* 指针。
n-- 要被复制的字节数。
返回值
该函数返回一个指向目标存储区destin的指针。
从源source所指的内存地址的起始位置开始拷贝n个字节到目标destin所指的内存地址的起始位置中。
memcpy( ) 并不关心被复制的数据类型,只是逐字节地进行复制,这给函数的使用带来了很大的灵活性,可以面向任何数据类型进行复制。
需要注意的是:
destin指针要分配足够的空间,也即大于等于 n 字节的空间。如果没有分配空间,会出现断错误。
destin和 source所指的内存空间不能重叠(如果发生了重叠,使用 memmove( )会更加安全)。

#include <string.h>
uint8_t source_data[8];
for(uint8_t i =0;i<8;i++)
{
   source_data[i]=i+1;
}
uint8_t dest_data[4];
memcpy(dest_data,source_data,4);
for(uint8_t i = 0;i<4;i++)
{
   qDebug()<<dest_data[i];//1234
}

8. strcat,strncat

字符串拼接函数
char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t n);

char dst[128]="hello";
char src[128]="world";
strcat(dst, src);
printf("%s\n", dst);//helloworld

9. strcmp,strncmp

字符串比较函数

两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇'\0'为止
将s1指向的字符串 和 s2指向的字符串 逐个字符比较
相等返回0;大于返回 >0;小于返回<0;
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);

char str1_1[128]="hello";
char str2_1[128]="hello";
printf("%d\n", strcmp(str1_1, str2_1));//0

char str1_5[100]="hello";
char str2_5[128]="hello";
printf("%d\n", strcmp(str1_5, str2_5));//0

char str1_2[128]="hello";
char str2_2[128]="w";
printf("%d\n", strcmp(str1_2, str2_2));//-1

char str1_3[128]="hello";
char str2_3[128]="o";
printf("%d\n", strcmp(str1_3, str2_3));//-1

char str1_4[128]="o";
char str2_4[128]="hello";
printf("%d\n", strcmp(str1_4, str2_4));//1

10. strchr字符查找函数

在参数str所指向的字符串中搜索第一次出现字符c(一个无符号字符)的位置,区分大小写。
char *strchr(const char *str, int c);
str-- 要被检索的 C 字符串
c-- 在str 要搜索的字符。
返回一个指向该字符串中第一次出现的字符的指针,如果字符串中不包含该字符则返回NULL空指针。

#include <string.h>
char str[17];
char *ptr,c='c';
strcpy(str,"abcdefgh");
ptr=strchr(str,c);
if(ptr)
{
   printf("The character %c is at position:%s\n",c,ptr);//The character c is at position:cdefgh
   printf("The character %c is at position:%d\n",c,ptr-str);//2  所查找的字符出现的位置,从0开始数
}
else
{
   printf("The character was not found\n");
}

11. strstr字符串查找函数

C库函数 char *strstr(const char *haystack, const char *needle)
在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 '\0'。
如果没有查找到返回NULL。

#include <stdio.h>
#include <string.h>

const char haystack[20] = "abcde1234fg";
const char needle[10] = "cde";

char *find_str1 = strstr(haystack,needle);
char *find_str2 = strstr(haystack,"fg");

int pos1 = find_str1 - haystack;

int pos2 = find_str2 - haystack;

printf("find_str1:%s\n", find_str1);//cde123fg
printf("find_str2:%s\n", find_str2);//fg
printf("pos1:%d\n", pos1);//2
printf("pos2:%d\n", pos2);//9

char want_str[10];
int want_str_size = pos2 - pos1 - 3; //3 是"cde"的长度
strncpy(want_str,find_str1+3,want_str_size);
want_str[want_str_size] = '\0';

printf("want_str:%s\n", want_str);//1234

屏蔽某些字符

char msg[] = "http://www.abc.abc.999.abc.com.cn";
char word[] = "abc";
int  size= strlen(word);//3

printf("%s\n", msg);//http://www.abc.abc.999.abc.com.cn

char *start = msg;
char *ret = NULL;

while(ret = strstr(start, word))
{
	memset(ret, '*', size);
	start = ret + size;

}
printf("%s\n", msg);//http://www.***.***.999.***.com.cn

12. strtok字符串切割函数

char *strtok(char *str, const char *delim);
str:指向被切的字符串的首元素地址
delim:为分隔符字符(如果传入字符串,则传入的字符串中每个字符均为分割符)
切割成功:返回切割到的子串 首元素地址
失败返回NULL
字符串切割,按照 delim 指向的字符串中的字符,切割 str 指向的字符串。
其实就是在 str 指向的字符串中发现了 delim 字符串中的字符,就将其变成’\0’,
调用一次 strtok 只切割一次,切割一次之后,再去切割的时候 strtok 的第一个参数传NULL,
意思是接着上次切割的位置继续切.

#include <string.h>

char msg[]="hehe:haha:xixi:lala";
char *buf[128]={NULL};

int i=0;
//第一次切割
buf[i] = strtok(msg, ":");

//第二次切割
while(buf[i] != NULL)//上一次切割正常,才进行下一次切割
{
	i++;
	buf[i] = strtok(NULL, ":");
}

//遍历切割到的字符串
i=0;
while(buf[i] != NULL)
{
	printf("%s\n", buf[i]);
	i++;
}
//    hehe
//    haha
//    xixi
//    lala

13. sprintf格式化为字符串

int sprintf(char *string, char *format [,argument,...]);
把格式化的数据写入某个字符串缓冲区。
format 标签属性是%[flags][width][.precision][length]specifier
返回值,如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。

注意两点:

1. 用 sprintf 转换数据量比较大的参数,建议用字符数组来存,不要用指针存。

2. sprintf 中使用到的数组全部定义成全局数组。--- 此条存疑

char str1[100];
char str2[100];
char dst[500];

strcpy(str1,"Erlab");
strcpy(str2,"kserlab@2018");
sprintf(dst,"AT+CWJAP_DEF=\"%s\",\"%s\"\r\n",str1,str2);

printf("%s", dst);//AT+CWJAP_DEF="Erlab","kserlab@2018"
char dst1[20];
char dst2[20];
char dst3[20];

int ret = 0;
double pi = 3.1415626;
ret = sprintf(dst1,"%06.3f",pi);//6位长度,3位小数,位数不够前面补零
printf("ret=%d,dst1=%s\n",ret,dst1);//ret=6,dst1=03.142

ret = sprintf(dst2,"%.3f",pi);//保留3位小数
printf("ret=%d,dst2=%s\n",ret,dst2);//ret=5,dst2=3.142

ret = sprintf(dst3,"%-06.3f",pi);
printf("ret=%d,dst3=%s\n",ret,dst3);//ret=6,dst3=3.142
//在Qt编译器下
#include <stdio.h>
char buf[32];
int data = 123456789;
std::sprintf(buf,"%d",data);

转化16进制两位数

char hex_data[2];
sprintf(hex_data,"%02X",6);
printf("hex_data:%s\n",hex_data);//06

sprintf 改进的函数snprintf

#include <stdio.h>
char a[16];
size_t i;

i = snprintf(a, 5, "%0d", 12345);  // 第 1 种情况
printf("i = %lu, a = %s\n", i, a); // 输出:i = 5, a = 1234

i = snprintf(a, 3, "%0d", 12345);   // 第 2 种情况
printf("i = %lu, a = %s\n", i, a);  // 输出:i = 5, a = 12

14. sscanf

sscanf读取格式化的字符串中的数据。
int sscanf( const char *buffer, const char *format, [ argument ] ... );
buffer  存储的数据
format  窗体控件字符串。 有关详细信息,请参阅"格式规范"。
argument  可选自变量
locale  要使用的区域设置
函数将返回成功赋值的字段个数;返回值不包括已读取但未赋值的字段个数。
返回值为 0 表示没有将任何字段赋值。 如果在第一次读取之前到达字符串结尾,则返回EOF。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char buf[512] = ;
sscanf("123456 ", "%s", buf);
printf("%s\n", buf);//123456

sscanf("123456 ", "%4s", buf);//取最大长度为4字节的字符串
printf("%s\n", buf);//1234

sscanf("123456 abcdedf", "%[^ ]", buf);//取遇到空格为止字符串
printf("%s\n", buf);//123456

sscanf("123456abcdedfBCDEF", "%[1-9a-z]", buf);//取仅包含1到9和小写字母的字符串
printf("%s\n", buf);//123456abcdedf

sscanf("123456abcdedfBCDEF", "%[^A-Z]", buf);//取遇到大写字母为止的字符串。
printf("%s\n", buf);//123456abcdedf

//给定一个字符串iios/12DDWDFF@122,获取 / 和 @ 之间的字符串,先将 "iios/"过滤掉,再将非'@'的一串内容送到buf中
sscanf("iios/12DDWDFF@122", "%*[^/]/%[^@]", buf);
printf("%s\n", buf);//12DDWDFF
结果为:12DDWDFF

//给定一个字符串"hello, world",仅保留"world"。(注意:“,”之后有一空格)
sscanf("hello, world", "%*s%s", buf);
printf("%s\n", buf);
//结果为:world  P.S. %*s表示第一个匹配到的%s被过滤掉,即hello,被过滤了,如果没有空格则结果为NULL

int day, year;
char weekday[20], month[20], dtm[100];
strcpy( dtm, "Saturday March 25 1989" );
sscanf( dtm, "%s %s %d  %d", weekday, month, &day, &year );
printf("%s %d, %d = %s\n", month, day, year, weekday );//March 25, 1989 = Saturday

二、应用举例

1. 截取字符串

解析出ssid和password的值

har msg[]="Smart get wifi info ssid:abcdepassword:123456";

char dst[500];
char *ptr;
ptr = strstr(msg,"ssid");
if(ptr != NULL)
{
    strcpy(dst,ptr);
    printf("%s\n",dst);//ssid:abcdepassword:123456

    int total_size = strlen(dst);
    int pos2 = strstr(dst,"password")-dst;

    printf("size:%d\n",total_size);//25
    printf("pos2:%d\n",pos2);//10

    char dst1[50];
    uint8_t len1 = strlen("ssid:");
    strncpy(dst1,dst+len1,pos2-len1);
    printf("%s\n",dst1);//abcde


    char dst2[50];
    uint8_t len2 = strlen("password:");
    strncpy(dst2,dst+pos2+len2,total_size-pos2-len2);
    printf("%s\n",dst2);//123456


}
posted @ 2024-11-14 11:10  ike_li  阅读(18)  评论(0编辑  收藏  举报