第 4 章 串(文本行编辑实现)

1. 背景说明

该文本编辑器利用串的堆实现,其中对串的原始存储方式基本不作修改(有部分修改之处),优化之处在于在串的末尾加上了一个空字符,目的是区分字符串结尾,便于将串保存在文件中,且该优化不对原来的功能造成影响,利用了二者的优点。

关键点在于从文件中读出字符串将其保存在串中和将串保存在文件中的处理方式,其实现原理图如下。

2. 示例代码

1) status.h

/* DataStructure 预定义常量和类型头文件 */#ifndef STATUS_H
#define STATUS_H#define CHECK_NULL(pointer) if (!(pointer)) { \printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NULL_PTR); \return NULL; \
}#define CHECK_RET(ret) if (ret != RET_OK) { \printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ret); \return ret; \
}#define CHECK_VALUE(value, ERR_CODE) if (value) { \printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_CODE); \return ERR_CODE; \
}#define CHECK_FALSE(value, ERR_CODE) if (!(value)) { \printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_CODE); \return FALSE; \
} /* 函数结果状态码 */
#define TRUE 					1			/* 返回值为真 */
#define FALSE 					0			/* 返回值为假 */
#define RET_OK 					0			/* 返回值正确 */
#define INFEASIABLE    		   	2			/* 返回值未知 */
#define ERR_MEMORY     		   	3			/* 访问内存错 */
#define ERR_NULL_PTR   			4			/* 空指针错误 */
#define ERR_MEMORY_ALLOCATE		5			/* 内存分配错 */
#define ERR_NULL_STACK			6			/* 栈元素为空 */
#define ERR_PARA				7			/* 函数参数错 */
#define ERR_OPEN_FILE			8			/* 打开文件错 */
#define ERR_NULL_QUEUE			9			/* 队列为空错 */
#define ERR_FULL_QUEUE			10			/* 队列为满错 */
#define ERR_NOT_FOUND			11			/* 表项不存在 */
typedef int Status;							/* Status 是函数的类型,其值是函数结果状态代码,如 RET_OK 等 */
typedef int Bollean;						/* Boolean 是布尔类型,其值是 TRUE 或 FALSE */#endif // !STATUS_H

2)  hString.h

/* 串的堆分配存储实现头文件 */#ifndef HSTRING_H
#define HSTRING_H#include "status.h"typedef struct {char *ch;int length;
} HString;/* 初始化(产生空串)字符串 T */
void InitString(HString *T);/* 生成一个其值等于串常量 chars 的串 T */
Status StrAssign(const char *chars, HString *T);/* 初始条件: 串 S 存在操作结果: 由串 S 复制得串 T */
Status StrCopy(const HString *S, HString *T);/* 初始条件: 串 S 存在操作结果: 若 S 为空串,则返回 TRUE,否则返回 FALSE */
Bollean StrEmpty(const HString *S);/* 若 S > T,则返回值 > 0;若 S = T,则返回值 = 0;若 S < T,则返回值 < 0 */
int StrCompare(const HString *S, const HString *T);/* 返回 S 的元素个数,称为串的长度 */
int StrLength(const HString *S);/* 将 S 清为空串 */
Status ClearString(HString *S);/* 用 T 返回由 S1 和 S2 联接而成的新串 */
Status Concat(const HString *S1, const HString *S2, HString *T);/* 用 Sub 返回串 S 的第 pos 个字符起长度为 len 的子串其中,1 ≤ pos ≤ StrLength(S) 且 0 ≤ len ≤ StrLength(S) - pos + 1 */
Status SubString(const HString *S, int pos, int len, HString *Sub);/* 算法 4.1,T 为非空串。若主串 S 中第 pos 个字符之后存在与 T 相等的子串则返回第一个这样的子串在 S 中的位置,否则返回 0 */
int Index(const HString *S, const HString *T, int pos);/* 算法 4.4, 在串 S 的第 pos 个字符之前插入串 T, 1 ≤ pos ≤ StrLength(S) + 1 */
Status StrInsert(const HString *T, int pos, HString *S);/* 从串 S 中删除第 pos 个字符起长度为 len 的子串 */
Status StrDelete(int pos, int len, HString *S);/* 初始条件: 串 S, T 和 V 存在, T 是非空串(此函数与串的存储结构无关)操作结果: 用 V 替换主串 S 中出现的所有与 T 相等的不重叠的子串 */
Status Replace(const HString *T, const HString *V, HString *S);/* 堆分配类型的字符串无法销毁(结构体)*/
void DestroyString(void);/* 输出 T 字符串 */
void StrPrint(const HString *T);#endif // !HSTRING_H

3) hString.c

/* 串的堆分配存储实现源文件 */#include "hString.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>/* 初始化(产生空串)字符串 T */
void InitString(HString *T)
{T->length = 0;T->ch = NULL;
}/* 生成一个其值等于串常量 chars 的串 T */
Status StrAssign(const char *chars, HString *T)
{CHECK_VALUE(!chars, ERR_NULL_PTR);if (T->ch) {free(T->ch);}int length = (int)strlen(chars);if (length == 0) {T->ch = NULL;T->length = 0;return RET_OK;}T->ch = (char *)malloc(sizeof(char) * (unsigned long long )(length + 1));CHECK_VALUE(!(T->ch), ERR_MEMORY_ALLOCATE);T->length = length;T->ch[length] = '\0';for (int i = 0; i < length; ++i) {T->ch[i] = chars[i];}return RET_OK;
}/* 初始条件: 串 S 存在操作结果: 由串 S 复制得串 T */
Status StrCopy(const HString *S, HString *T)
{CHECK_VALUE(!S || !T, ERR_NULL_PTR);if (T->ch) {free(T->ch);}T->ch = (char *)malloc(sizeof(char) * (unsigned long long)(S->length + 1));CHECK_VALUE(!(T->ch), ERR_MEMORY_ALLOCATE);T->length = S->length;T->ch[S->length] = '\0';for (int i = 0; i < S->length; ++i) {T->ch[i] = S->ch[i];}return RET_OK;
}/* 初始条件: 串 S 存在操作结果: 若 S 为空串,则返回 TRUE,否则返回 FALSE */
Bollean StrEmpty(const HString *S)
{return ((S->length == 0) && (S->ch == NULL)) ? TRUE : FALSE;
}/* 若 S > T,则返回值 > 0;若 S = T,则返回值 = 0;若 S < T,则返回值 < 0 */
int StrCompare(const HString *S, const HString *T)
{CHECK_VALUE(!S || !T, ERR_NULL_PTR);for (int i = 0; i < S->length && i < T->length; ++i) {if (S->ch[i] != T->ch[i]) {return S->ch[i] - T->ch[i];}}return S->length - T->length;
}/* 返回 S 的元素个数,称为串的长度 */
int StrLength(const HString *S)
{return S->length;
}/* 将 S 清为空串 */
Status ClearString(HString *S)
{if (S->ch) {free(S->ch);S->ch = NULL;}S->length = 0;return RET_OK;
}/* 用 T 返回由 S1 和 S2 联接而成的新串 */
Status Concat(const HString *S1, const HString *S2, HString *T)
{CHECK_VALUE(!S1 || !S2 || !T, ERR_NULL_PTR);if (T->ch) {free(T->ch);}int length = S1->length + S2->length;T->ch = (char *)malloc(sizeof(char) * length);CHECK_VALUE(!(T->ch), ERR_MEMORY_ALLOCATE);for (int i = 0; i < S1->length; ++i) {T->ch[i] = S1->ch[i];}for (int i = 0; i < S2->length; ++i) {T->ch[S1->length + i] = S2->ch[i];}T->length = length;return RET_OK;
}/* 用 Sub 返回串 S 的第 pos 个字符起长度为 len 的子串其中,1 ≤ pos ≤ StrLength(S) 且 0 ≤ len ≤ StrLength(S) - pos + 1 */
Status SubString(const HString *S, int pos, int len, HString *Sub)
{CHECK_VALUE(!S || !Sub, ERR_NULL_PTR);CHECK_VALUE((pos < 1) || (pos > S->length) || (len < 0) || (len > S->length - pos + 1), ERR_PARA);if (Sub->ch) {free(Sub->ch);}if (len == 0) {Sub->ch = NULL;Sub->length = 0;} else {Sub->ch = (char *)malloc(sizeof(char) * (unsigned long long)(len + 1));CHECK_VALUE(!(Sub->ch), ERR_MEMORY_ALLOCATE);for (int i = 0; i < len; ++i) {Sub->ch[i] = S->ch[pos - 1 + i];}Sub->length = len;Sub->ch[Sub->length] = '\0';}return RET_OK;
}/* 算法 4.1,T 为非空串。若主串 S 中第 pos 个字符之后存在与 T 相等的子串则返回第一个这样的子串在 S 中的位置,否则返回 0 */
int Index(const HString *S, const HString *T, int pos)
{int maxRange = StrLength(S) - StrLength(T) + 1;CHECK_VALUE((pos < 1) || (pos > maxRange), 0);HString sub;InitString(&sub);while (pos <= maxRange) {SubString(S, pos, StrLength(T), &sub);if (StrCompare(&sub, T) != 0) {++pos;} else {return pos;}}return 0;
}/* 算法 4.4, 在串 S 的第 pos 个字符之前插入串 T, 1 ≤ pos ≤ StrLength(S) + 1 */
Status StrInsert(const HString *T, int pos, HString *S)
{CHECK_VALUE(!T || !S, ERR_NULL_PTR);CHECK_VALUE((pos < 1) || (pos > S->length + 1), ERR_PARA);if (T->length == 0) {return RET_OK;}S->ch = (char *)realloc(S->ch, sizeof(char) * (unsigned long long)(S->length + T->length + 1));CHECK_VALUE(!(S->ch), ERR_MEMORY_ALLOCATE);for (int i = S->length - 1; i >= pos - 1; --i) {S->ch[i + T->length] = S->ch[i];}S->length += T->length;for (int i = 0; i < T->length; ++i) {S->ch[pos - 1 + i] = T->ch[i];}S->ch[S->length] = '\0';return RET_OK;
}/* 从串 S 中删除第 pos 个字符起长度为 len 的子串 */
Status StrDelete(int pos, int len, HString *S)
{CHECK_VALUE(!S, ERR_NULL_PTR);CHECK_VALUE(pos - 1 + len > S->length, ERR_PARA);for (int i = pos - 1; i < S->length - len; ++i) {S->ch[i] = S->ch[i + len];}S->length -= len;S->ch = (char *)realloc(S->ch, sizeof(char) * (unsigned long long)(S->length + 1));S->ch[S->length] = '\0';return RET_OK;
}/* 初始条件: 串 S, T 和 V 存在, T 是非空串(此函数与串的存储结构无关)操作结果: 用 V 替换主串 S 中出现的所有与 T 相等的不重叠的子串 */
Status Replace(const HString *T, const HString *V, HString *S)
{CHECK_VALUE(!T || !V || !S, ERR_NULL_PTR);int pos = 1;do {pos = Index(S, T, pos);if (pos) {StrDelete(pos, StrLength(T), S);StrInsert(V, pos, S);pos += StrLength(V);}} while (pos);return RET_OK;
}/* 堆分配类型的字符串无法销毁(结构体)*/
void DestroyString(void)
{printf("Do not need to destroy!\n");
}/* 输出 T 字符串 */
void StrPrint(const HString *T)
{for (int i = 0; i < T->length; ++i) {putchar(T->ch[i]);}
}

4) textEditing.h

/* 文本行编辑实现头文件 */#ifndef TEXTEDITING_H
#define TEXTEDITING_H#include "hString.h"#define MAX_LINE_NUM 25
#define MAX_CHAR_NUM 75
#define NAME_LEN 20/* 显示文件内容 */
void ShowText(int lineNum, const HString *T);/* 插入新行 */
Status InsertNewLine(int *lineNum, HString *T);/* 删除内容 */
Status DeleteContent(int *lineNum, HString *T);/* 拷贝文件内容 */
Status CopyContent(int *lineNum, HString *T);/* 修改文本行 */
Status ModifyContent(int lineNum, HString *T);/* 查找字符串 */
Status SearchContent(int lineNum, const HString *T);/* 替换字符串 */
Status ReplaceContent(int lineNum, HString *T);/* 将文本行同步到文件中 */
Status SaveToFile(int nameLength, const char *fileName, int lineNum, const HString *T);/* 显示主菜单 */
void ShowMainMenu(void);/* 显示子菜单 */
void ShowSubMenu(void);/* 初始化 */
Status MainMenu(int nameLength, int maxLine, char *fileName, int *lineNum, HString *T);#endif // !TEXTEDITING_H

5) textEditing.c

/* 文本行编辑实现源文件 */#include "textEditing.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>/* 获取最多 n - 1 个字符保存在 str 指向的内存中 */
static char *SGets(int n, char *str)
{char *retVal = fgets(str, n, stdin);if (retVal) {char *find = strchr(str, '\n');if (find) {*find = '\0';} else {while (getchar() != '\n') {continue;}}}return retVal;
}/* 打开已存在文件或创建新文件 */
static Status OperateFile(int nameLength, const char *fileName)
{CHECK_VALUE(!fileName, ERR_NULL_PTR);CHECK_VALUE(nameLength > NAME_LEN, ERR_PARA);FILE *fp;errno_t err_ret = fopen_s(&fp, fileName, "ab+");CHECK_VALUE(err_ret != RET_OK, ERR_OPEN_FILE);fclose(fp);return RET_OK;
}/* 从文件中读取文本行 */
static Status ReadFromFile(int nameLength, const char *fileName, int *lineNum, HString *T)
{CHECK_VALUE(!fileName || !T, ERR_NULL_PTR);CHECK_VALUE((nameLength > NAME_LEN), ERR_PARA);FILE *fp;errno_t err_ret = fopen_s(&fp, fileName, "rb");CHECK_VALUE(err_ret != RET_OK, ERR_OPEN_FILE);char str[MAX_CHAR_NUM + 1];*lineNum = 0;Status ret = RET_OK;while ((fgets(str, MAX_CHAR_NUM + 1, fp) != NULL) && (*lineNum <= MAX_LINE_NUM)) {str[strlen(str) - 1] = '\0';ret = StrAssign(str, T + *lineNum);if (ret != RET_OK) {fclose(fp);break;}++(*lineNum);}CHECK_VALUE(ret != RET_OK, ret);fclose(fp);return RET_OK;
}/* 显示文件内容 */
void ShowText(int lineNum, const HString *T)
{for (int i = 0; i < lineNum; ++i) {printf("Line %d: ", i + 1);StrPrint(T + i);putchar('\n');}
}/* 在第 pos 行前插 num 行 */
static Status InsertLine(int pos, int num, const char str[][MAX_CHAR_NUM], HString *T, int *lineNum)
{CHECK_VALUE((*lineNum + num > MAX_LINE_NUM) || ((pos < 1) || (pos > (*lineNum + 1))), ERR_PARA);Status ret = RET_OK;for (int i = *lineNum - 1; i >= pos - 1; --i) {ret = StrCopy(T + i, T + i + num);CHECK_VALUE(ret != RET_OK, ret);}for (int i = 0; i < num; ++i) {CHECK_VALUE(strlen(str[i]) > MAX_CHAR_NUM, ERR_PARA);StrAssign(str[i], T + pos - 1 + i);++(*lineNum);}return RET_OK;
}/* 插入新行 */
Status InsertNewLine(int *lineNum, HString *T)
{printf("Please input the position(Line Before) you want to insert and the line num: ");int pos, num;scanf_s("%d%d", &pos, &num);getchar();CHECK_VALUE((*lineNum + num > MAX_LINE_NUM) || ((pos < 1) || (pos > (*lineNum + 1))), ERR_PARA);char str[MAX_LINE_NUM][MAX_CHAR_NUM] = { 0 };for (int i = 0; i < num; ++i) {printf("Please input the %dth string: ", i + 1);SGets(MAX_CHAR_NUM, str[i]);}Status ret = InsertLine(pos, num, str, T, lineNum);CHECK_VALUE(ret != RET_OK, ret);return RET_OK;
}/* 删除文本行 */
static Status DeleteLine(int pos, int num, HString *T, int *lineNum)
{CHECK_VALUE(!T || !lineNum, ERR_NULL_PTR);CHECK_VALUE((pos <= 0) || (pos > *lineNum - num + 1), ERR_PARA);for (int i = pos - 1 + num; i < *lineNum; ++i) {StrCopy(T + i, T + i - num);}*lineNum -= num;return RET_OK;
}/* 删除内容 */
Status DeleteContent(int *lineNum, HString *T)
{printf("Please input the pos(From) and num you want to delete: ");int pos, num;scanf_s("%d%d", &pos, &num);getchar();Status ret = DeleteLine(pos, num, T, lineNum);CHECK_VALUE(ret != RET_OK, ret);return RET_OK;
}/* 把第 pos 行开始的 num 行插在原 insPos 行之前 */
static Status CopyLine(int pos, int num, int insPos, HString *T, int *lineNum)
{CHECK_VALUE(!T || !lineNum, ERR_NULL_PTR);CHECK_VALUE((pos < 1) || (pos > *lineNum - num + 1) || (insPos < 1) || (insPos > *lineNum + 1)|| (*lineNum + num > MAX_LINE_NUM), ERR_PARA);char str[MAX_LINE_NUM][MAX_CHAR_NUM] = { 0 };for (int i = 0; i < num; ++i) {(void)strcpy_s(str[i], MAX_CHAR_NUM, (T + pos - 1 + i)->ch);}Status ret = InsertLine(insPos, num, str, T, lineNum);CHECK_VALUE(ret != RET_OK, ret);return RET_OK;
}/* 拷贝文件内容 */
Status CopyContent(int *lineNum, HString *T)
{CHECK_VALUE(!T || !lineNum, ERR_NULL_PTR);printf("Please input the pos and num and insPos: ");int pos, num, insPos;scanf_s("%d%d%d", &pos, &num, &insPos);getchar();Status ret = CopyLine(pos, num, insPos, T, lineNum);CHECK_VALUE(ret != RET_OK, ret);return RET_OK;
}static ModifyLine(const char *str, int pos, HString *T)
{Status ret = StrAssign(str, T + pos - 1);CHECK_VALUE(ret != RET_OK, ret);return ret;
}/* 修改文本行 */
Status ModifyContent(int lineNum, HString *T)
{CHECK_VALUE(!T, ERR_NULL_PTR);printf("Please input the pos you want to modify: ");int pos;scanf_s("%d", &pos);getchar();CHECK_VALUE((pos < 1) || (pos > lineNum), ERR_PARA);printf("Please input the content you want to fill: ");char str[MAX_CHAR_NUM];SGets(MAX_CHAR_NUM, str);Status ret = ModifyLine(str, pos, T);CHECK_VALUE(ret != RET_OK, ret);return ret;
}static Status SearchString(const char *str, int lineNum, const HString *T)
{HString s;InitString(&s);StrAssign(str, &s);Bollean continueFind = TRUE;for (int i = 0; (i < lineNum) && continueFind; ++i) {int start = 1;while (start) {start = Index(T + i, &s, start);if (start) {printf("Find in Line %d: ", i + 1);StrPrint(T + i);printf(" ,Find in %dth position\n", start);printf("Continue find?(Y/N) ");if (getchar() != 'Y') {getchar();continueFind = FALSE;break;}++start;getchar();}}}if (continueFind) {printf("Not find!\n");}return RET_OK;
}/* 查找字符串 */
Status SearchContent(int lineNum, const HString *T)
{CHECK_VALUE(!T, ERR_NULL_PTR);printf("Please input the string you want to find: ");char str[MAX_CHAR_NUM] = { 0 };SGets(MAX_CHAR_NUM, str);Status ret = SearchString(str, lineNum, T);CHECK_VALUE(ret != RET_OK, ret);return ret;
}static Status ReplaceString(const char *str, const char *strInstead, int lineNum, HString *T)
{HString s, sInstead;InitString(&s);InitString(&sInstead);StrAssign(str, &s);StrAssign(strInstead, &sInstead);int lengthChange = (int)(strlen(strInstead) - strlen(str));Bollean continueFind = TRUE;for (int i = 0; (i < lineNum) && continueFind; ++i) {int start = 1;while (start) {start = Index(T + i, &s, start);if (start) {CHECK_VALUE(StrLength(T + i) + lengthChange > MAX_CHAR_NUM, ERR_PARA);printf("Find in Line %d: ", i + 1);StrPrint(T + i);printf(" ,Find in %dth position\n", start);StrDelete(start, (int)strlen(str), T + i);StrInsert(&sInstead, start, T + i);printf("Continue replace?(Y/N) ");if (getchar() != 'Y') {getchar();continueFind = FALSE;break;}++start;getchar();}}}if (continueFind) {printf("Not find!\n");}return RET_OK;
}/* 替换字符串 */
Status ReplaceContent(int lineNum, HString *T)
{CHECK_VALUE(!T, ERR_NULL_PTR);printf("Please input the string you want to replace: ");char str[MAX_CHAR_NUM] = { 0 };SGets(MAX_CHAR_NUM, str);printf("Please input the string you want to instead: ");char strInstead[MAX_CHAR_NUM] = { 0 };SGets(MAX_CHAR_NUM, strInstead);Status ret = ReplaceString(str, strInstead, lineNum, T);CHECK_VALUE(ret != RET_OK, ret);return ret;
}/* 将文本行同步到文件中 */
Status SaveToFile(int nameLength, const char *fileName, int lineNum, const HString *T)
{CHECK_VALUE(!fileName || !T, ERR_NULL_PTR);CHECK_VALUE((nameLength > NAME_LEN) || (lineNum > MAX_LINE_NUM), ERR_PARA);FILE *fp;errno_t err_ret = fopen_s(&fp, fileName, "wb");CHECK_VALUE(err_ret != RET_OK, ERR_OPEN_FILE);char *str = NULL;for (int i = 0; i < lineNum; ++i) {fputs(T[i].ch, fp);fputc(10, fp);}fclose(fp);return RET_OK;
}/* 显示主菜单 */
void ShowMainMenu(void)
{printf("Main Menu:\n");printf("1. Open file(New or Existed)\n");printf("0. Exit system\n");
}/* 显示子菜单 */
void ShowSubMenu(void)
{printf("Sub Menu:\n");printf("1. Show text\n");printf("2. Insert new line\n");printf("3. Delete line\n");printf("4. Copy existed line\n");printf("5. Modify existed line\n");printf("6. Find string\n");printf("7. Replace string\n");printf("8. Save to file\n");printf("0. Exit to main menu\n");
}/* 初始化 */
Status MainMenu(int nameLength, int maxLine, char *fileName, int *lineNum, HString *T)
{CHECK_VALUE(!fileName || !lineNum || !T, ERR_NULL_PTR);CHECK_VALUE((nameLength > NAME_LEN) || (maxLine > MAX_LINE_NUM), ERR_PARA);printf("Please input the file name: ");SGets(NAME_LEN, fileName);OperateFile(nameLength, fileName);ReadFromFile(nameLength, fileName, lineNum, T);ShowText(*lineNum, T);return RET_OK;
}

6) main.c

/* 入口程序源文件 */#include "textEditing.h"
#include <stdio.h>
#include <string.h>int main(void)
{char fileName[NAME_LEN] = { 0 };HString T[MAX_LINE_NUM] = { 0 };for (int i = 0; i < MAX_LINE_NUM; ++i) {InitString(T + i);}int lineNum = 0;int mainChoose = 1, subChoose = 1;while (mainChoose) {printf("\n");ShowMainMenu();printf("Please input you choose: ");scanf_s("%d", &mainChoose);getchar();switch (mainChoose) {case 1:MainMenu((int)strlen(fileName), MAX_LINE_NUM, fileName, &lineNum, T);subChoose = 1;while (subChoose) {printf("\n");ShowSubMenu();printf("Please input your choose: ");scanf_s("%d", &subChoose);getchar();switch (subChoose) {case 1:ShowText(lineNum, T);break;case 2:InsertNewLine(&lineNum, T);break;case 3:DeleteContent(&lineNum, T);break;case 4:CopyContent(&lineNum, T);break;case 5:ModifyContent(lineNum, T);break;case 6:SearchContent(lineNum, T);break;case 7:ReplaceContent(lineNum, T);break;case 8:SaveToFile((int)strlen(fileName), fileName, lineNum, T);break;case 0:break;}}break;case 0:break;}}for (int i = 0; i < MAX_LINE_NUM; ++i) {ClearString(T + i);}return 0;
}

3. 运行示例

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/140700.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

K8S:Pod容器中的存储方式及PV、PVC

文章目录 Pod容器中的存储方式一&#xff0e;emptyDir存储卷1.emptyDir存储卷概念2.emptyDir存储卷示例 二.hostPath存储卷1.hostPath存储卷概念2.hostPath存储卷示例 三.nfs共享存储卷1.nfs共享存储卷示例 四.PV和PVC1.PV、PVC概念2.PVC 的使用逻辑及数据流向3.storageclass插…

公众号迁移多久可以完成?

公众号账号迁移的作用是什么&#xff1f;只能变更主体吗&#xff1f;长期以来&#xff0c;由于部分公众号在注册时&#xff0c;主体不准确的历史原因&#xff0c;或者公众号主体发生合并、分立或业务调整等现实状况&#xff0c;在公众号登记主体不能对应实际运营人的情况下&…

c#:System.Text.Json 的使用三(从Newtonsoft迁移)

环境&#xff1a; .net 6.0vs2022 系列篇&#xff1a; 《c#&#xff1a;System.Text.Json 的使用一》 《c#&#xff1a;System.Text.Json 的使用二》 《c#&#xff1a;System.Text.Json 的使用三&#xff08;从Newtonsoft迁移&#xff09;》 参考&#xff1a; 《MSDN: 从 Newt…

【GO】LGTM_Grafana_gozero_配置trace(4)_代码实操及追踪

最近在尝试用 LGTM 来实现 Go 微服务的可观测性&#xff0c;就顺便整理一下文档。 Tempo 会分为 4 篇文章&#xff1a; Tempo 的架构官网测试实操跑通gin 框架发送 trace 数据到 tempogo-zero 微服务框架发送数据到 tempo 本文就是写一下如何在 go-zero 微服务框架里面配置 t…

C++ list容器的实现及讲解

所需要的基础知识 对C类的基本了解 默认构造函数 操作符重载 this指针 引用 模板等知识具有一定的了解&#xff0c;阅读该文章会很轻松。 链表节点 template<class T>struct list_node{T _data;list_node<T>* _next;list_node<T>* _prev;list_node(const T&…

顺序表的实现和练习

杂谈&#xff1a; 有些数据结构&#xff08;C语言实现&#xff09;的教材/教程中会使用C中引用的语法&#xff0c;引用确实在形式上比指针简洁&#xff0c;这样做无非是为了避免后续对二级指针的使用。 我认为既然使用C语言实现数据结构&#xff0c;那么指针就不应该是门槛。…

关于地址存放的例题

unsigned int a 0x1234; unsigned char b *(unsigned char*)&a; 上面代码大端存储和小端存储的值分别是多少&#xff1f; 大端存储的是把高位地址存放在低位地址处&#xff0c;低位存放到高位。小端是高位存放在高位&#xff0c;低位在低位。因为a是整型&#xff0c;所…

Kafka的消息存储机制

前面咱们简单讲了K啊开发入门相关的概念、架构、特点以及安装启动。 今天咱们来说一下它的消息存储机制。 前言&#xff1a; Kafka通过将消息持久化到磁盘上的日志文件来实现高吞吐量的消息传递。 这种存储机制使得Kafka能够处理大量的消息&#xff0c;并保证消息的可靠性。 1…

vue重修003

文章目录 版权声明day03一、今日目标1.生命周期2.综合案例-小黑记账清单3.工程化开发入门4.综合案例-小兔仙首页 二、Vue生命周期三、Vue生命周期钩子四、生命周期钩子小案例1.在created中发送数据2.在mounted中获取焦点 五、案例-小黑记账清单1.需求图示&#xff1a;2.需求分析…

ChatGPT批量写作文章软件

什么是ChatGPT批量写作文章。简单来说&#xff0c;它是一种使用ChatGPT技术的方法&#xff0c;可以帮助您批量生成各种类型的文章和内容。无论您是需要新闻报道、博客文章、产品描述、社交媒体帖子还是其他类型的内容&#xff0c;ChatGPT都能满足您的需求。它可以在极短的时间内…

探索 GO 项目依赖包管理与Go Module常规操作

探索 GO 项目依赖包管理与Go Module常规操作 文章目录 探索 GO 项目依赖包管理与Go Module常规操作一.Go 构建模式的演变1.1 GOPATH &#xff08;初版&#xff09;1.1.1 go get 1.2 vendor 机制&#xff08;中版&#xff09;1.3 Go Module&#xff08;最新版&#xff09; 二.创…

C语言 cortex-A7核UART总线实验

一、C 1&#xff09;uart4.h #ifndef __UART4_H__ #define __UART4_H__ #include "stm32mp1xx_rcc.h" #include "stm32mp1xx_gpio.h" #include "stm32mp1xx_uart.h&quo…

4k、VR与万兆光网

“全光万兆”对VR意义重大。 pico4的分辨率 PICO 4 的单眼分辨率是 2160 2160&#xff0c;整体分辨率高达 4320 2160。这是一款高性能的 VR 一体机&#xff0c;采用了 2.56 英寸的 Fast-LCD 屏幕&#xff0c;最高可实现 90Hz 刷新率&#xff0c;还有 1200 PPI 和 20.6 PPD 的…

基于海康Ehome/ISUP接入到LiveNVR实现海康摄像头、录像机视频统一汇聚,做到物联网无插件直播回放和控制

LiveNVR支持海康NVR摄像头通EHOME接入ISUP接入LiveNVR分发视频流或是转GB28181 1、海康 ISUP 接入配置2、海康设备接入2.1、海康EHOME接入配置示例2.2、海康ISUP接入配置示例 3、通道配置3.1、直播流接入类型 海康ISUP3.2、海康 ISUP 设备ID3.3、启用保存3.4、接入成功 4、相关…

Mac磁盘空间满了怎么办?Mac如何清理磁盘空间

你是不是发现你的Mac电脑存储越来越满&#xff0c;甚至操作系统本身就占了100多G的空间&#xff1f;这不仅影响了电脑的性能&#xff0c;而且也让你无法存储更多的重要文件和软件。别担心&#xff0c;今天这篇文章将告诉你如何清除多余的文件&#xff0c;让你的Mac重获新生。 一…

Nginx的location作用

location Nginx 的 locaiton 作⽤是根据⽤户请求的 URI 不同&#xff0c;来执行不同的应用。针对用户请求的网站URL 进行匹配&#xff0c;匹配成功后进行对应的操作。 location [ | ~| ~* | ^~ ] url {#指定对应的动作 } 正则表达式解释 匹配符 匹配规则 优先级 精确匹配 1…

数据结构——二叉树层序遍历

链式二叉树的建立 前言一、层序遍历的概念和实现二、判断二叉树是否是完全二叉树总结 前言 来喽来喽~ 二叉树的层序遍历来喽~ 层序遍历那是相当有趣滴&#xff01; 我的朋友&#xff0c;请不要迷惘&#xff0c;你要记住&#xff0c;你终有鲲鹏一日&#xff01; 加油吧&#xf…

详解MySQL存储引擎

前言: 📕作者简介:热爱编程的小七,致力于C、Java、Python等多编程语言,热爱编程和长板的运动少年! 📘相关专栏Java基础语法,JavaEE初阶,数据库,数据结构和算法系列等,大家有兴趣的可以看一看。 😇😇😇有兴趣的话关注博主一起学习,一起进步吧! 一、MySQL存…

修改vscode底部栏背景和字体颜色

修改vscode底部栏背景和字体颜色 如图&#xff1a; 首先打开齿轮&#xff0c;打开设置搜索workbench.colorCustomizations,然后点击编辑setting.json修改setting.json内内容 "workbench.colorCustomizations": {"statusBar.foreground": "#FFFFFF…

5G通信与蜂窝模组之间的关系

5G通信是第五代移动通信技术的简称&#xff0c;它代表了一种新一代的无线通信技术标准。5G通信的主要目标是提供更高的数据传输速度、更低的延迟、更大的网络容量以及更可靠的连接&#xff0c;以支持各种新兴应用和服务&#xff0c;包括高清视频流、虚拟现实、物联网&#xff0…