1.strtok_s函数原型
strtok_s 是一个线程安全的字符串分割函数,它是 strtok 的一个变体,用于将字符串分割成一系列的标记(tokens)。与 strtok 不同,strtok_s 需要一个额外的参数来保存上下文信息,这样它就可以在不同的调用之间保持状态,而不需要使用静态变量。这使得 strtok_s 更加适合在多线程环境中使用。
strtok_s 的函数原型通常如下:
char *strtok_s(char *str, const char *delim, char **saveptr);
str:要分割的字符串。对于第一次调用,它应该是指向要分割的字符串的指针;对于后续的调用,它应该是 NULL。
delim:包含分隔符的字符串。 saveptr:指向一个 char * 的指针,用于保存上下文信息。在第一次调用时,它应该指向一个有效的
char * 变量(通常是一个局部变量),该变量将被 strtok_s 用于存储状态信息。在后续的调用中,你应该将 saveptr
的值保持不变,并直接传递给 strtok_s。
函数的工作原理如下:
在第一次调用时,strtok_s 会在 str 中查找第一个不属于 delim 中的字符,并将其视为标记的开始。然后它会继续查找直到遇到
delim 中的字符或字符串的末尾,此时它会将找到的标记的末尾设置为空字符(\0),并返回指向标记的指针。同时,它会在内部更新
saveptr 指向的位置,以便下次调用时能够继续从正确的位置开始搜索。 在后续的调用中(即当 str 为 NULL 时),strtok_s
会使用 saveptr 中保存的信息来继续搜索下一个标记。它会从 saveptr 指向的位置开始,跳过任何属于 delim
的字符,然后查找下一个标记。 当没有更多的标记可以找到时,strtok_s 将返回 NULL。
以下是一个使用 strtok_s 的示例:
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "This is a test string.";
char *token;
char *rest = str; // 用于保存 strtok_s 的上下文
// 分割字符串并打印每个标记
while ((token = strtok_s(rest, " ", &rest)) != NULL) {
printf("Token: %s\n", token);
}
return 0;
}
在这个示例中,字符串 “This is a test string.” 被空格分割成了多个标记,并且每个标记都被打印出来。注意,rest 变量被用作 strtok_s 的上下文保存器,并在每次调用时都传递给函数。在第一次调用时,rest 指向要分割的原始字符串;在后续的调用中,rest 会被 strtok_s 更新为指向下一个要搜索的位置。
2.实现使用strtok_s分割字符串,并返回包含分割符的子串
一定要理解,strtok_s的本质是拷贝一个副本,然会在副本上做字符替换,把分割符替换成’\0’.
实现使用strtok_s分割字符串,并返回包含分割符的子串:
思路是token是每次调用strtok_s返回的分割后的子串,那么可以计算该子串的长度。在原始字符串中,使用该长度就可以找到原始字符串中,分割符是哪个。再使用该分割符和token拼接成包含分割符的子串。返回即可。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char get_first_char_before_delimiter(const char* str, const char* delimiter) {
const char* pos = strstr(str, delimiter); // Find the position of the delimiter in the string
if (pos != NULL && pos != str) { // Ensure the delimiter is found and not at the very beginning
return *(pos - 1); // Return the character just before the delimiter
}
else {
// If the delimiter is not found or is at the beginning, return a special value
return '\0'; // Or you can handle it differently, e.g., by returning an error code
}
}
// 函数声明
char get_left_char(const char* str, const char* address);
// 函数定义
char get_left_char(const char* str, const char* address) {
if (address == str) {
// 地址指向字符串的第一个字符,没有左边紧接着的字符
return NULL;
}
else {
// 返回左边紧接着的字符的地址
return *((char*)(address - 1));
}
}
// Function to split string by delimiters and return an array of substrings
char** split_string(const char* str, const char* delimiters, int* count) {
char* copy = (char*)malloc(strlen(str) + 1); // Allocate memory for the copy of the input string
if (!copy) {
perror("Failed to allocate memory for copy");
return NULL;
}
strcpy(copy, str); // Copy the input string to avoid modifying it
char* token, * rest = copy;
char** result = NULL;
int capacity = 10; // Initial capacity for result array
int idx = 0;
result = (char**)malloc(capacity * sizeof(char*));
if (!result) {
perror("Failed to allocate memory for result");
free(copy);
return NULL;
}
int len = 0,init = 1;
while ((token = strtok_s(rest, delimiters, &rest))) {
char tempstr;
if (init)
{
init = 0;
tempstr = get_first_char_before_delimiter(str, token);
} else{
tempstr = *(str + len);
}
len = len + strlen(token) + 1;
printf("str =%c\n", tempstr);
char* new_token = (char*)malloc(strlen(token) + 2); // Allocate memory for the new token
if (!new_token) {
perror("Failed to allocate memory for token");
for (int i = 0; i < idx; i++) {
free(result[i]);
}
free(result);
free(copy);
return NULL;
}
char strArray[2] = {'\0'};
strArray[0] = tempstr;
strcpy(new_token, strArray);
strcat(new_token, token); // Copy the token to the new memory location
result[idx++] = new_token;
if (idx >= capacity) {
capacity *= 2;
result = (char**)realloc(result, capacity * sizeof(char*));
if (!result) {
perror("Failed to reallocate memory for result");
for (int i = 0; i < idx; i++) {
free(result[i]);
}
free(result);
free(copy);
return NULL;
}
}
}
*count = idx;
free(copy);
return result;
}
// Function to free the array of substrings
void free_split_string(char** strings, int count) {
for (int i = 0; i < count; i++) {
free(strings[i]);
}
free(strings);
}
int main()
{
const char* str = "?VT=100!PT=20?ADT=100&30";
const char* delimiters = "!?&";
int count;
char** substrings = split_string(str, delimiters, &count);//str
if (substrings) {
for (int i = 0; i < count; i++) {
printf("cmd=%s\n", substrings[i]);
}
}
return 0;
}
运行结果: