0.0 常用函数库_字符串处理及快排

编程总结

每每刷完一道题后,其思想和精妙之处没有地方记录,本篇博客用以记录刷题过程中的遇到的算法和技巧

字符串函数汇总

memcpy_s

函数原型
errno_t memcpy_s(void *dest, size_t destSize, const void *src, size_t count);
函数描述
memcpy_s 函数,从 src 中复制 count 个字节到 dest 中。它是 memcpy 的安全版本,因为参数中限制了目标内存区域的大小。是在内存级别上直接进行拷贝操作,但注意它一次拷贝的数量为一个字节,而不是一个位(比特)。
参数描述
dest: 目标数组,或者说目标内存区域
destSize:目标内存区域的大小,其单位是字节
src: 源数组,或者说源内存区域
count: 要复制的源内存区域元素的个数,其单位是字节
返回值
如果成功则返回零(EOK)

memset_s

函数原型
errno_t memset_s(void *dest,rsize_t destsz,int ch,rsize_t count)
函数描述
1)将ch值(在转换为无符号字符后,就像通过(unsigned char)ch)复制到dest指向的对象的每个第一个计数字符中。
如果访问超出dest数组的末尾,则行为未定义。如果dest是空指针,行为是未定义的。
2)与(1)相同,只是在运行时检测到以下错误,并且如果dest和destsz本身有效,则在将ch存储到目标范围[dest,dest + destsz)的每个位置之后调用当前安装的约束处理函数:
参数描述
dest: 指向要填充的对象的指针
ch: 填充字节
count:要填充的字节数
destsz: 目标数组的大小
返回值
1)dest 副本
2)如果成功则返回零(EOK),错误时为非零。 同样出错的是,如果dest不是空指针并且destsz有效,那么将destsz填充字节ch写入目标数组

strncpy_s

函数原型
errno_t strncpy_s(char *restrict dest,rsize_t destsz,const char *restrict src,rsize_t count)
函数描述
1)将由src指向的字符数组的大部分计数字符(包括终止空字符,但不包括空字符后面的任何字符)复制到由dest指向的字符数组。如果在复制完整个数组src之前达到count,则生成的字符数组不会以null结尾。
如果在复制src中的终止空字符之后,未达到count,则将额外的空字符写入dest,直到写入总计数字符。
如果字符数组重叠,如果dest或src不是指向字符数组的指针(包括如果dest或src是空指针),如果dest指向的数组大小小于count,则行为未定义, 或者如果src指向的数组大小小于count并且不包含空字符。
2)与(1)相同,除了该函数不会继续将零写入目标数组以填充计数,它将在写入终止空字符后停止(如果源中没有空值,它将在dest处写入一个 [count]然后停止)。
参数描述
dest: 指向要复制到的字符数组的指针
destsz: 目标缓冲区的大小
src: 指向要复制的字符数组的指针
count: 最大数量的字符复制
返回值
1)返回 dest 副本
2)在成功时返回零(EOK),错误时返回非零值。 另外,如果出错,则将0写入dest [0](除非dest为空指针或destsz为零或大于RSIZE_MAX),并可能用未指定的值来摧毁目标数组的其余部分

strcat_s

函数原型
errno_t strncat_s(char *restrict dest,rsize_t destsz,const char *restrict src,rsize_t count)
函数描述
1)追加由src指向的字符数组中的大多数计数字符,如果找到空字符,则停止到由dest指向的以null结尾的字节字符串的末尾。 字符src [0]替换dest结尾处的空终止符。 终止空字符总是附加在最后(因此函数可以写入的最大字节数为count + 1)。
如果目标数组没有足够的空间用于dest和src的第一个计数字符的内容以及终止的空字符,则行为未定义。 如果源和目标对象重叠,则行为未定义。 如果dest不是指向以空字符结尾的字节字符串的指针,或者src不是指向字符数组的指针,则行为未定义.
2)与(1)相同,只是此函数可能会打断目标数组的其余部分(从写入到destsz的最后一个字节开始),并且在运行时检测到以下错误并调用当前安装的约束处理函数。
参数描述
dest: 指向要附加到的以空字符结尾的字节字符串
destsz: 目标缓冲区的大小
src: 指向要复制的字符数组的指针
count 最大数量的字符复制
返回值
1)返回 dest 副本
2)在成功时返回零(EOK),错误时返回非零值。 另外,如果发生错误,则将零写入dest [0](除非dest是空指针或destsz为零或大于RMAX_SIZE)。

strtok_s

函数原型
char *strtok_s(char *restrict str,rsize_t *restrict strmax,const char *restrict delim,char **restrict ptr)
函数描述
1)在由str指向的以空字符结尾的字节字符串中查找下一个标记。 分隔符字符由delim指向的以空字符结尾的字节字符串标识。该函数被设计为被称为倍数时间以从相同的字符串获得连续的令牌。
如果str!= NULL,则该调用被视为针对此特定字符串的第一次调用strtok。该函数搜索不在delim中的第一个字符。
如果没有找到这样的字符,那么str中就没有令牌了,并且该函数返回一个空指针。
如果找到这样的字符,它就是令牌的开始。然后该函数从此处开始搜索包含在delim中的第一个字符。
如果没有找到这样的字符,str只有一个标记,未来对strtok的调用将返回一个空指针
如果找到这样的字符,它将被替换为空字符’\ 0’,并且指向以下字符的指针将存储在静态位置以供后续调用。
该函数然后将指针返回到令牌的开始处如果str == NULL,则该调用将被视为对strtok的后续调用:该函数将继续前一次调用中的离开。行为与先前存储的指针作为str传递的行为相同。如果str或delim不是指向以空字符结尾的字节字符串的指针,则行为未定义。
2)与(1)相同,除了在每一步中,将留在str中的字符数写入* strmax并将标记器的内部状态写入* ptr。 重复调用(使用null str)必须将strmax和ptr与先前调用所存储的值一起传递。 此外,在运行时检测到以下错误,并调用当前安装的约束处理函数,而不在ptr指向的对象中存储任何内容
参数描述
str: 指向以空字符结尾的字节字符串进行标记的指针
delim: 指向标识分隔符的以空字符结尾的字节串的指针
strmax: 指向最初保存str大小的对象的指针:strtok_s存储待检查的字符数
ptr: 指向char *类型的对象的指针,strtok_s用它来存储它的内部状态

返回值
返回指向下一个标记开头的指针,如果没有其他标记,则返回NULL。

sprintf_s

函数原型
int sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, ...);
函数描述
1)在由str指向的以空字符结尾的字节字符串中查找下一个标记。 分隔符字符由delim指向的以空字符结尾的字节字符串标识。该函数被设计为被称为倍数时间以从相同的字符串获得连续的令牌。
如果str!= NULL,则该调用被视为针对此特定字符串的第一次调用strtok。该函数搜索不在delim中的第一个字符。
如果没有找到这样的字符,那么str中就没有令牌了,并且该函数返回一个空指针。
如果找到这样的字符,它就是令牌的开始。然后该函数从此处开始搜索包含在delim中的第一个字符。
如果没有找到这样的字符,str只有一个标记,未来对strtok的调用将返回一个空指针
如果找到这样的字符,它将被替换为空字符’\ 0’,并且指向以下字符的指针将存储在静态位置以供后续调用。
该函数然后将指针返回到令牌的开始处如果str == NULL,则该调用将被视为对strtok的后续调用:该函数将继续前一次调用中的离开。行为与先前存储的指针作为str传递的行为相同。如果str或delim不是指向以空字符结尾的字节字符串的指针,则行为未定义。
2)与(1)相同,除了在每一步中,将留在str中的字符数写入* strmax并将标记器的内部状态写入* ptr。 重复调用(使用null str)必须将strmax和ptr与先前调用所存储的值一起传递。 此外,在运行时检测到以下错误,并调用当前安装的约束处理函数,而不在ptr指向的对象中存储任何内容
参数描述
buffer 输出的存储位置
sizeOfBuffer 可存储的最多字符数。
format 格式控件字符串
… 要设置格式的可选参数
locale 要使用的区域设置。
返回值
写入的字符数或 -1(如果发生错误)。 如果 buffer 或 format 是 null 指针,sprintf_s 和 swprintf_s 将返回 -1 并将 errno 设置为 EINVAL。
sprintf_s 返回存储在 buffer中的字节数,不包括终止 null 字符。 swprintf_s 返回存储在 buffer 中的宽字符数,不包括中止 null 宽字符。

int main( void )
{
   char  buffer[200], s[] = "computer", c = 'l';
   int   i = 35, j;
   float fp = 1.7320534f;
   // Format and print various data:
   j  = sprintf_s(buffer,     200,     "   String:    %s\n", s );
   j += sprintf_s(buffer + j, 200 - j, "   Character: %c\n", c );
   j += sprintf_s(buffer + j, 200 - j, "   Integer:   %d\n", i );
   j += sprintf_s(buffer + j, 200 - j, "   Real:      %f\n", fp );
   printf_s( "Output:\n%s\ncharacter count = %d\n", buffer, j );
}
Output:
   String:    computer
   Character: l
   Integer:   35
   Real:      1.732053
character count = 79

strncmp

函数原型
int strncmp(const char *str1, const char *str2, size_t n)
函数描述
strncmp函数为字符串比较函数 ,功能是将str1和str2进行比较,最多比较n个字节。若str1与str2的前n个字符相同,则返回0;若s1大于s2,则返回大于0的值;若s1 小于s2,则返回小于0的值。
参数描述
str1 – 要进行比较的第一个字符串。
str2 – 要进行比较的第二个字符串。
n – 要比较的最大字符数
返回值
str1=str2 返回0
str1>str2 返回大于0的数
str1<str2 返回小于0的数

函数Demo_字符函数

#define BUFFER_SIZE  128

int safetyFunction(char *s)
{
    int len = strlen(s);
    if (len <= 1) {
        return len;
    }
    errno_t rc;
    char hashtable1[BUFFER_SIZE]  = {false};
    char hashtable2[BUFFER_SIZE]  = {"@123@1234@12345@"};
    char hashtable3[BUFFER_SIZE]  = {"12345678"};
    // 1. errno_t memcpy_s(void* dest, size_t destMax, const void* src, size_t count)
    rc = memcpy_s(hashtable1, BUFFER_SIZE, hashtable2, BUFFER_SIZE - 1);
    if (rc != EOK) {
        return -1;
    }
    // 2.errno_t memset_s(void* dest, size_t destMax, int c, size_t count)
    rc = memset_s(hashtable1, BUFFER_SIZE, '1', BUFFER_SIZE);
    if (rc != EOK) {
        return -1;
    }
    // 3.errno_t strcpy_s(char* strDest,size_t destMax,const char* strSrc)
    rc = strncpy_s(hashtable1, BUFFER_SIZE, "The Love of the game",  BUFFER_SIZE);
    if (rc != EOK) {
        return -1;
    }
    // 4.errno_t strcat_s(char* strDest,size_t destMax,const char* strSrc)
    rc = strcat_s(hashtable1, BUFFER_SIZE, "Make the choice");
    if (rc != EOK) {
        return -1;
    }

    // 5.char* strtok_s(char* strToken, const char* strDelimit, char** context)
    // 成功:返回被分割出的子字符串首地址(当子字符串长度等于0时返回NULL)
    // 失败:当参数不合法或找到的子字符串长度为0时,返回NULL。
    char *next = NULL; // 保存调用strok_s后的位置信息
    char *token = NULL;
    const char *plim = "@";
    token = strtok_s(hashtable2, plim, &next);
    while (token != NULL) {
        if (token != NULL) {
            printf(" %s\n", token);
            token = strtok_s(NULL, plim, &next);
        }
    }

    // 6.int sprintf_s(char *strDest, size_t destMax, const char *format, ...) -- 将数据格式化输出到目的缓冲区。
    // 成功:操作成功时,返回写入的字符个数
    char buffer[BUFFER_SIZE] = {0};
    char *string    = "Kobe Kobe";
    int  intString  = 20201204;
    int  iRet;
    iRet = sprintf_s(buffer, BUFFER_SIZE, "%s, %d", string, intString);
    printf("iRet = %d, buffer = %s.\n", iRet, buffer);
    iRet = atoi(hashtable3);
    return len;
}
int main()
{
    const char *str = "abcabcd";
    safetyFunction(str);
}

sprintf_s 还可以组合多个不同格式的统一到字符数组里:

 tmp = atoi(res);
 sprintf_s(result, NUM_9, "%08d", tmp);
 sprintf_s(node[cnt].buf, NUM_9 + 1, "%c%08s", strs[i][0], result);

qsort函数

手法1:qsort可以用来排序结构体

a -b 的顺序就是从小往大

typedef struct student {
    int height;
    int weight;
    int id;
} student_t;
int cmp(const void *a, const void *b)
{
    student_t *aa = (student_t *)a;
    student_t *bb = (student_t *)b;
	// 3. 如果身高、体重都相同,则按ID排序 
    if (aa->height == bb->height && aa->weight == bb->weight) {
        return (aa->id - bb->id); // 由小往大排序
    }
    // 2. 身高相同,体重不同,按体重排序
    if (aa->height == bb->height) {
        return (aa->weight - bb->weight);
    }
	// 1. 身高、体重均不同,优先按身高排序
    return (aa->height - bb->height);
}
qsort(stu, num, sizeof(student_t), cmp);

手法2:在排序字符串时,我们可以利用qsort的cmp,这么来写,可以做字典序由低至高排序:

int cmp(const void *a, const void *b)
{
    jobNumber *aa = (jobNumber *)a;
    jobNumber *bb = (jobNumber *)b;
    return strncmp(aa->buf, bb->buf, BUF_LEN);
}

手法3:对 double / float 数组升序排序

以上方法对 double 型则不适用,因为 cmp 返回值为 int 型,若两个小数差距极小,例如:a=0.15 ,b=0.14,将会被强制转换为0返回,不发生交换。

double 与 float 需要转成 1 和 -1

int cmp(const void *a, const void *b)
{
  if(*(double *)a > *(double *)b) {
    return 1;
  }
  else if(*(double *)a < *(double *)b) {
    return -1;
  }
  return 0;
}

整数的翻转

字符串的翻转我们有手法处理,这里记录下整数的翻转,当然只是我自己的方法,并不是Golden的,有好的建议的朋友可以指出来。主要用到 sprintf_s 函数

// 反转一个整数
int numFanzhuan(int num)
{
    int i;
    int len = 0;
    char str[STR_MAX_LEN]    = {0};
    char strTmp[STR_MAX_LEN] = {0};
    int  res;
    sprintf_s(str, STR_MAX_LEN, "%d", num);

    for (i = 0; i < STR_MAX_LEN; i++) {
        if (str[i] != '\0') {
            len++;
        }
    }
    for (i = 0; i < len; i++) {
        strTmp[i] = str[len - 1 - i];
    }
    res = atoi(strTmp);

    return res;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值