中文字符占用字节即相关原理(实现中文(中英混合)字符串的反转)

如有不对欢迎指正。 

目录

 一.ASCLL字符和中文字符

1.使用无符号数表示的原因(对于中文字符): 

2.但是并不是所有情况都是用无符号数(以下目前只是猜测,如有问题欢迎指正) :

1. 什么时候使用无符号数表示:     

2. 不需要使用的情况: 

3.我们上面说到的char是有符号类型,可我们平时使用可以直接表示字符呀? 

 二.对于中文字符,将一个字符串的中文字符传给另一个

三.实现中文字符串的反转 

方法一 :  

方法二:   


 一.ASCLL字符和中文字符

char类型

char类型我们在写代码的时候经常会使用,它用于存储定义一个存储字符的变量,但是我们定义char类型一般是用来存放一些英文字符等,这些字符都有一个特点:都是ASCLL中指定的字符。 

说是字符其实存储的是一些二进制数,我们知道一个字节有八位,一位可以存储0,1两个二进制位,所以八位一共可以表示2^8 = 256 个数据,但是,对于ASCLL码我们使用的一般是128个,所以只需要低7位即可存储下。最高位存0即可。(后面新增的(128-255)有些编码可能不兼容)

所以,char定义的变量只能用来存放ASCLL码表中的字符,所以char类型的变量只占一个字节。(因为一个字节就足够表示全部ASCLL码的值,不需要再多占用内存了)。 

那么怎么能让这128个数据和字符对照起来呢,其实就是一个查表的过程(可以看下ASCLL码表) 。

但是,由于历史原因,ASCLL码表中是没有中文字符的, (所以我们无法使用char类型的变量来表示一个中文字符)。为了能够使用中文字符,衍生出了GBK,GB2312等编码字符集,这些字符集兼容ASCLL码字符(只兼容前127个,后新增的不兼容)。

1.使用无符号数表示的原因(对于中文字符): 

因为ASCLL码字符已经基本占用了一个字节的内存来表示相应的字符,再加上中华文化博大精深,一个字节(最多才256个数据)怎么能放的下我们的汉字呢,所以中文字符使用两个字节来保存(大部分) ,而且为了能够确定你输出的是中文字符,相应编码做出了不同的规定。其中一个是:两个字节的高第一个字节必须为1(这也就说明了,存放这些数据需要一个无符号类型(因为有符号最高位是表示正负的,会出问题)--后面会说到)。GBK和GB2312都是如此。(当然其它不同编码可能会有不同--但是依然使用无符号数进行表示数据)。

2.但是并不是所有情况都是用无符号数(以下目前只是猜测,如有问题欢迎指正)

1. 什么时候使用无符号数表示:     

当我们需要使用字符对应的二进制数据进行数学运算和比较的时候,我们使用无符号数据最好。

2. 不需要使用的情况: 

当我们只是想通过二进制输出对应的字符时(平时定义字符,输出都属于这一类型)。我们可以不需要考虑有无符号。 

其实大部分情况下都不需要使用,我们平时也遇到很多,例如: 我们使用一个char a[] = "我爱你",对于这个字符串,就是一个包含7个字节的字符串,每个字节是一个char类型的空间,如果如上述(使用无符号数的原因)我们表示这个字符串,应该使用无符号类型才行,但是使用过的都知道,我们直接去输出这个字符串也是没有问题的。(也就是说,我们使用char这样的符号类型,它也能正确的查表)。

举一个例子,char类型字符的取值范围是 -128  ---  127 ,当我们赋值超过127其就是一个负数了,那么按照上述所说(使用无符号数表示),应该是无法正确表示出字符的。但是经过测试之后发现是没有问题的,(但是由于我们默认使用的代码页(一般为936),是不包括新增的128-255位ASCLL码,所以输出需要修改代码页(看代码)), 


int main(void)
{SetConsoleOutputCP(437);char a = 254;printf("%c", a);system("pause");return 0;
}

上述代码,进行了代码页的转换,否则无法输出128-255位的ASCLL码数(因为是新增的不兼容),我们看代码 -- 使用char类型,赋值为254,但由于前面char类型的范围,这个值是溢出的,所以实际它的值为:-2, 原码: 1000 0010, 补码: 1111 1110, 我们如果将其补码看作无符号数转换成数字,为254。

当我们以字符形式输出时,会发现可以正常输出,而且正好是ASCLL码第254号位置的字符。 

 就是本图的正方形。

结论:  所以,1)我们数据在计算机中以补码形式存储,那么计算机在查表时(表中为无符号数),不会区分正负,(如果只是根据二进制输出相应字符,不需要考虑符号)只是看该数据与表中哪个数据对应,然后输出对应的字符。

2)只有在我们使用字符对应的二进制数据计算,比较,以有符号数输出时才会有明确的正负。建议使用无符号类型。(这些都是自己的猜测,如果不对请指正)。  

所以,这也说明了,如果一个中文字符对应的二进制数据,最高位都为1的话(有符号类型应该是个负数),我们使用char类型输出字符串时却没有问题。 

3.对于使用使用无符号数表示字符对应的数据(就是二进制组成的数字),可能会有疑问。 

3.我们上面说到的char是有符号类型,可我们平时使用可以直接表示字符呀? 

原因 :  上面说到过,ASCLL一般使用低七位即可,最高位一般为0.

 如图。 作为无符号数,最高位为0的时候为正数,它和其对应的无符号数表示的值是一样的(如果为1就不一样了,多一个负号吗),所以我们平时使用char也是可以的。

 二.对于中文字符,将一个字符串的中文字符传给另一个

对于字符串, 定义:  char  s[] = "我爱你";   char s2[100] = {0}(定义了一个占用100字节的数组); 我们要将s指向的字符串拷贝到s2中。

1.2.首先, 我们上面说到一个中文字符占用两个字节,一个char占用一个字节,

 

如上图,一个框子为一个字节(最后\0表示字符串的结束) ,所以对于字符数组,s它存储的字符串虽然只有三个元素,但是它却占七个字节(还有一个字符串结束符)。

从这可以更加直观的看出,为什么不能使用char来打印中文字符了,人家占用两个位置,你只给一个位置,不出问题才怪。 

2.想要将s中的字符串拷贝到s2中,与直接拷贝ASCLL字符不一样,但是也差不多。 

一个汉字占用两个字节,我们只需要将这两个字节按照顺序拷贝到s2中即可。例: s2[0] = s1[0],

s2[1] = s1[1] -- 后面的中文一起类推,最后加一个字符串结束符就可以了。(原因:其实一个汉字,对应的是这两个字节所组成的0,1数字组合,然后对应查表就可得到,此处,我们按照顺序,将这些数字组合拷贝到目标数组--它们的顺序是没有改变的所以对应的还是哪个汉字,所以实现了拷贝) 

对于字符串的输出,编译器使用相应的编码,所以可以输出中文等。 

三.实现中文字符串的反转 

方法一 :  

#include <iostream>
#include <Windows.h>
#include <string>
#include <errno.h>
#include <string.h>using namespace std;#define STRTEMPLEN 30char* exchangeChineseStr(const char* str);/*字符串常量的值为首字符的地址,使用指针+一个字符占用字节数,可以跳过相应字节输出后面字符串,中文字符一个占用两个
字节,所以+2*/int main(void)
{string str;char* result = NULL;cout << "请输入一个字符串" << endl;cin >> str;// 错误检测if (cin.fail()){cerr << "输入失败,原因:" << strerror(errno) << endl;exit(1);}if ((result = exchangeChineseStr(str.c_str())) != NULL){printf("%s\n", result);  //输出乱码的原因: 是因为返回了局部变量}system("pause");return 0;
}char* exchangeChineseStr(const char* str)
{if (str == NULL){cout << "传入字符串为空" << endl;return NULL;}int len = strlen(str);  // 计算长度//printf("%d", len); char strTemp[STRTEMPLEN] = { 0 };strcat(strTemp, str);  // 得到字符串的字节数char strReturn[STRTEMPLEN] = { 0 };//printf("%s\n",strReturn);for (int i = len; i > 0; i -= 2)  // 中文字符占两个字节,所以一次加2才能找到下一个字符,否则会出现乱码。{//printf("%s", strTemp);   //printf("%s", strTemp + 4);     strcat(strReturn, (strTemp + (i-2)));  *(strTemp + (i-2)) = '\0';  // 一个汉字占用两个字节,将这两个字节都设置为0*(strTemp + (i-1)) = '\0';}char* a = strReturn;printf("%s\n", a);return strReturn;
}

上面的代码,利用了中文字符串占两个字节的特性,从源字符串的尾部,以字符串的形式拼接到目的字符串的尾部,拼接之后将此位置设置成\0,然后再拼接下一位,直至结束。 (如图)

方法二:   

 此方法可以实现中文和英文混合反转。

#include <iostream>
#include <Windows.h>
#include <string>using namespace std;/*实现中英文混合转换-- 由于中英文占用字节数不同,所以需要判断相应字符是英文还是中文*/
void reserve(unsigned char* str); /*对字符串进行反向*/int main(void)
{unsigned char a[] = "我爱你";reserve(a);system("pause");return 0;
}void reserve(unsigned char* str)
{int len = strlen((char *)str); // 计算传入字符串的字节数unsigned char temp[1024]; // 创建一个1024字节的数组,用来临时存放转换后的数组// 定义两个指针,分别对str和temp进行操作unsigned char* p1 = str;  // p1指向str的开头unsigned char* p2 = temp + len; /*因为temp数组很大,但其实我们只需要它能够存放str所占字节数+1就行(因为还有一个结束符),此时p2存放数 据的结尾是,temp+len(首元素+len,就是最后一个位置--存放'\0')*/*p2-- = '\0'; // 做后一位为'\0'while (*p1){if (*p1 < 0x80)   // *p1中的数小于127,说明是英文字符{*p2-- = *p1++;}else  // 否则是中文字符{*(p2 - 1) = *(p1++);*p2 = *(p1++);p2 -= 2;}}printf("%s", temp);
}

1. 我们要实现中英文混合转换,因为:中文和英文所占用的字节不同,所以转换的方式也有差距,所以,要分情况。 

首先, 我们前面我们说到,汉字的高位都是1,英文为ASCLL码高位为0,如果为无符号,那么汉字的每一个字节都应该大于127(0x80),-- 此处需要与数据进行比较,所以所有字符都定义成无符号类型(不使用无符号会出错,(不使用无符号,那就是有符号,在比较时,汉字对应数据都是负值,都比127小,就都以ASCLL字符算了肯定出错))所以,每一个字节,比127大的都是汉字字符,相反为英文字符,然后按照顺序将字符串拷贝到目标字符串即可。

注意: 因为是逆转,所以要从后向前拷贝,但是中文字符一定要注意,每个字符的每个字节顺序不能乱。 

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

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

相关文章

全渠道客服系统推荐:选型指南与最佳实践分享

售后服务是影响客户满意度的最直接的因素。有些企业不注重产品的售后服务&#xff0c;不仅是对客户的伤害&#xff0c;更是对企业品牌的损害。所以&#xff0c;做好售后服务对于企业来讲至关重要。 企业谈到做好售后服务&#xff0c;少不了一款好用的客服系统工具。其中&#…

【开源】基于Vue+SpringBoot的毕业生追踪系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 登陆注册模块2.2 学生基本配置模块2.3 就业状况模块2.4 学历深造模块2.5 信息汇总分析模块2.6 校友论坛模块 三、系统设计3.1 用例设计3.2 实体设计 四、系统展示五、核心代码5.1 查询我的就业状况5.2 初始化就业状况5.…

【VRTK】【VR开发】【Unity】17-创建立体UI

【背景】 游戏无法忽略的一个要素就是UI界面,本篇开始介绍VRTK这方面的能力。 VR游戏的UI和传统电视游戏UI的不同之处在于,VR游戏的UI必须融合在VR的游戏空间内,而传统电视游戏的UI则可以位于游戏画面的上层,位于屏幕的特定位置,比如表示人物血量等的图示等。不同于传统的…

jmeter的常用功能及在测试中的基本使用和压测实战

Jmeter基础功能 了解Jmeter的常用组件 元件&#xff1a;多个类似功能组件的容器&#xff08;类似于类&#xff09; 一&#xff1a;Test Plan&#xff08;测试计划&#xff09; 测试计划通常用来给测试的项目重命名&#xff0c;使用多线程脚本运行时还可以配置线程组运行方式…

uniapp的css样式图片大小截图展示

目录 截取图片前截取图片后第一种方式&#xff1a;代码第二种方式&#xff1a;代码最后 截取图片前 截取图片后 第一种方式&#xff1a;代码 <view class"swiper-box-img"><image class"swiper-box-img-img" :src"item.file_path" mod…

Xline command 去重机制(一)—— RIFL 介绍

为什么要对 command 去重&#xff1f; 在一个接收外部 command 的系统中&#xff0c;通常一个 command 至少要执行一次&#xff0c;我们称其为 at-least-once semantics。如果一个 command 执行失败&#xff0c;系统内部经常会实现一套重试结构来尝试恢复这个问题&#xff0c;…

09|链(下):想学“育花”还是“插花”?用RouterChain确定客户意图

09&#xff5c;链&#xff08;下&#xff09;&#xff1a;想学“育花”还是“插花”&#xff1f;用RouterChain确定客户意图 任务设定 首先&#xff0c;还是先看一下今天要完成一个什么样的任务。 这里假设咱们的鲜花运营智能客服 ChatBot 通常会接到两大类问题。 鲜花养护…

C1189#error: WinSock.h has already been included解决方案

最近在做项目移植过程中遇到这个报错&#xff0c;解决了半天。简单记录下解决方案&#xff0c;以供给大家提供一个思路。 原因&#xff1a; 在工程中使用了Boot库之后&#xff0c;使用了socket、tcp相关的头文件&#xff0c;在其他地方还是包括了头文件<windows.h>&…

分布式【4. 什么是 CAP?】

什么是 CAP&#xff1f; C 代表 Consistency&#xff0c;一致性&#xff0c;是指所有节点在同一时刻的数据是相同的&#xff0c;即更新操作执行结束并响应用户完成后&#xff0c;所有节点存储的数据会保持相同。 A 代表 Availability&#xff0c;可用性&#xff0c;是指系统提…

啊哈c语言——4.10、for隆重登场(一起来找茬)

下面这段代码是求12345678910的值。其中有4个错误&#xff0c; 快来改正吧&#xff01; 改正后&#xff1a; #include <stdio.h> #include <stdlib.h> int main( ) {int i, sum;sum1;for(i1; i<10;i){sumsum*i;}printf("%d", sum);system("paus…

express的基础使用,利用postman模拟后端路由

简介 Node.js 使 JavaScript\TypeScript 脚本能够脱离浏览器环境在服务端&#xff08;后端&#xff09;运行&#xff08;实际上是对 Chrome V8 引擎进行了封装&#xff09;&#xff0c;为我们开发后端提供了一种选项。不像前端有统一的浏览器标准&#xff0c;如果不遵循的话浏…

Linux下使用Wireshark抓包教程

在实际开发中&#xff0c;涉及网络传输的环节是非常多的。在这些过程中&#xff0c;我们经常有查看被传输的数据信息的需求&#xff0c;因此&#xff0c;抓包工具应运而生。Wireshark便是一款非常有名的抓包及分析软件&#xff0c;具有强大的协议解析能力。本文将介绍如何在Lin…