字符串拼接函数strcat的实现 while(*p++ !='\0')跳出后,p究竟指向哪? C/C++求职面试必备考点(三)...

strcat函数深入解析
本文详细探讨了strcat函数的内部实现机制,重点分析了指针操作中的*p++与++p的区别,通过实例代码展示了如何正确使用这些操作来实现字符串连接,并解释了为何在循环结束后指针的位置不是预期的位置。

在研究strcat函数实现的时候,发现了while(*p++ !=‘\0’)的大秘密,也让我发现了在上篇博客中我犯的一个错误。原以为跳出后,P指向'\0',而实际上并非如此!我按跳出后P指向'\0',结果怎么拼接都实现不了,NND。为了验证这个问题,我们先上个小程序吧:

#include<stdio.h>

void main()

{

char *p = "abcdefg";

while(*p++ != 'c');

printf("%c\n", *p);

}

您猜打印出来的是几? 结果是d。

为什么呢?

原来*和++的优先级是一样的,当优先级一样的时候,程序按自左至右的顺序执行。所以当*p = 'c' 或者*p = '\0'时,p仍然要往下移一位,即p指向满足条件后的下一个字节。

由于'\0' 结束符,if 、while当会把他判成0,因此程序写成while(*p++ );效果也一样,最终程序指向字符串结束符'\0'的下一字节。

如果这样写:

while(*p)

p++;

当*p='\0'时,进不到while里面的循环,因此这种写法跳出循环的时候,p指向的是'\0'。同志们注意了,这样写while后面是没有“;”号的,文章一开始的写法后面是有“;”号的。

所以明白了这,我们写strcat就好些了,首先查找目的字符串dst的末尾处,然后复制过去就OK了。

#include <stdio.h>

#include <assert.h>

char *strcat(char *dst, const char *src)

{

assert(dst);

char *dstFirst = dst;

while(*dst++);

dst--;

while(*dst++ = *src++);

return dstFirst;

}


//测试部分

void main()

{

char *str1 = "you must";

char *str2 = "zijuezizhi!";

char *dst = malloc(100);

strcat(strcat(dst, str1), str2);

prinf("%s\n", dst);

free(dst);

dst = NULL; 这个为什么大家指点奋斗

}

测试结果:you mustzijuezizhi! 一切正常。

char *dst = malloc(100); 这句话也可以这样写:char *dst = NULL; dst = (char *)malloc(100);在程序结束处一定要free(dst)啊!也有书上说在dst调用strcat之前,要*dst = '\0',我没这样,测试结果也正确。水平有限,有些问题解释不了,大神看到了指点一二。

这里交代下为甚strcat包括strcpy函数要返回char*类型,通过程序也看到了,返回的是首地址。我们printf打印一个字符串用的参数 就是首地址。因此通过返回首地址可以实现像strcat(strcat(dst, str1), str2);这种链式调用。在某些场合很方便。





#define _CRT_SECURE_NO_WARNINGS // fopen 打开文件,需要禁用安全警告 _crt_secure_no_warnings #include <stdio.h> // FILE 文件操作 #include <string.h> // strcat 字符串拼接 #include <stdlib.h> #include <direct.h> // _mkdir 目录生成 //#include <ctime> // time_t 存储时间 c++ 头文件,需要将当前运行的文件,改成 .cpp 文件,而不是 .c 文件 #include <time.h> #include "simple_c_string_algorithm/simple_c_string_algorithm.h" char git_path[256] = { 0 }; // git.txt 路径位置 char log_path[256] = { 0 }; // 日志路径 char* get_current_time(); // 前置声明 // 生成 对应的文件路径, 返回字符串 char* git_log_path() { // 单利模型下,有数据就不重复执行了 if (log_path[0] == '\0') // 第0个,是不是空字符串 { char tmp_path[256] = { 0 }; strcat_s(tmp_path, sizeof(tmp_path), "..\\log\\"); _mkdir(tmp_path); time_t now_time = time(NULL); // 获取本地时间 struct tm* t_tm = localtime(&now_time); time_t mk_time = mktime(t_tm); char buf[256] = { 0 }; char* p_time = _i64toa(mk_time, buf, 10); // 将 整型long 转成 10进制的 字符串 //char* p_time = get_current_time(); //remove_char_end(p_time, '\n'); // 移除 \n //remove_char_end(p_time, ':'); // 移除 : 冒号 const char file_suffix[] = ".txt"; strcat_s(tmp_path, strlen(p_time), p_time ); strcat_s(tmp_path, strlen(file_suffix), file_suffix); FILE* hfile = NULL; if ((hfile = fopen(tmp_path, "a+")) != NULL) { strcpy_s(log_path, sizeof(tmp_path), tmp_path); fclose(hfile); } } return log_path; } // 生成 git.txt 对应的文件路径,返回字符串 char* get_git_path() { // 单利模型下,有数据就不重复执行了 if (git_path == '\0') // 第0个,是不是空字符串 { char tmp_path[256] = { 0 }; // 字符串拼接 strcat_s(tmp_path, sizeof(tmp_path), "..\\.git\\"); // 生成目录 .git _mkdir(tmp_path); strcat_s(tmp_path, sizeof(tmp_path), "git.txt"); // 记录版本信息 FILE* hfile = NULL; // a 追加 + 可读可写 if ((hfile = fopen(tmp_path, "a+")) != NULL) { // 将 信息B 拷贝到 A strcpy_s(git_path, sizeof(git_path), tmp_path); fclose(hfile); } } return git_path; } // 获取当前本地时间 char* get_current_time() { return ctime(__TIME__); } // 写日志 void log_wirte(char const* content) { char* p = git_log_path(); FILE* hfile = NULL; // a 追加 + 可读可写 if ((hfile = fopen(p, "a+")) != NULL) { /* [12:34:32] 当前的操作成功 \n [12:34:32] 当前的操作成功 \n [12:34:32] 当前的操作成功 \n */ char* p = get_current_time(); // 获取时间 remove_char_end(p, '\n'); // 删除 \n char buf[1024] = { 0 }; // 追加字符 // 将第个参数 复制到第一个 参数里面去 strcpy_s(buf, sizeof(buf), "["); // 将第个参数,拼接到第一个参数后 strcat_s(buf, sizeof(buf), p); strcat_s(buf, sizeof(buf), "] "); strcat_s(buf, sizeof(buf), content); strcat_s(buf, sizeof(buf), "\r\n"); printf(buf); // 打印到屏幕 fprintf(hfile, buf); // 存储到文件中 fclose(hfile); } } // 初始化 void init_engine() { } // 退出 void exit_engine() { } // 引擎循化 void engine_loop() { char input_buff[1024] = { 0 }; int b_exit = 0; while (!b_exit) { printf("请输入指令:\r\n"); printf("\r\n"); // 接收输入的内容,并存储到 input_buff 中 fgets(input_buff, 1024, stdin); // 线程阻塞 // 去除前后空白 input_buff[strcspn(input_buff, "\r\n")] = '\0'; // 精确比较 if (strcmp(input_buff, "exit") == 0) // 不等于0 说明 找到了 exit { b_exit = 1; // 跳出循环,即刻退出 } else if (strstr(input_buff, "git init")) // 搜索字符,搜索到了返回指针 或 NULL { char* p = get_git_path(); log_wirte("当前 git 初始化成功!!"); } //printf("输入的内容是:"); //// 输出编写的内容 //fputs(input_buff, stdout); //printf("\r\n"); } } int main() { // 引擎初始化 init_engine(); // 循环 engine_loop(); // 退出 printf("引擎 退出;\r\n"); exit_engine(); system("pause"); return 0; } 报错:1>D:\UE\LibStudy\Project3\Project3\.c(92,23): warning C4133: “函数”: 从“char [9]”到“const time_t *const ”的类型不兼容 1>LINK : fatal error LNK1168: 无法打开 D:\UE\LibStudy\Project3\x64\Debug\Project3.exe 进行写入
最新发布
12-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值