字符串长度问题

欢迎加入我们,一同切磋技术。 &
用户名: &&&
密 码: &
共有 3023 人关注过本帖
标题:接收字符串问题
等 级:青峰侠
帖 子:358
专家分:1852
结帖率:100%
&&已结贴√
&&问题点数:20&&回复次数:6&&&
接收字符串问题
假设定义一个字符串str,以下两个字符串接收语句有什么区别啊?
scanf(&%s&,str);
gets(str);
貌似scanf不能接收空格,一遇到空格则判定字符串输入完毕,而gets可以接收空格,遇到回车时才判定字符串输入完毕,是这样吗?
搜索更多相关主题的帖子:
等 级:论坛游侠
帖 子:60
专家分:123
个人理解是这样……以前好像也验证过……
等 级:千里冰封
帖 子:1555
专家分:10000
&&得分:10&
另外,scanf将接收到的回车扔回到缓冲区,gets将接收到的回车符号转变为\0存入str,使用gets不检查字符串是否超出大小,存在安全问题,建议用fgets
#include&&&stdio.h&
#include&&&string.h&
int main(void){
&&& char str1[10]=&aaaaaaaaa&,str2[10]=&bbbbbbbbb&;
&&& scanf(&%s&,str1);
&&&// getchar();
&&& gets(str2);
&&& return 0;
这里面的getchar()就是为了接收扔回到缓冲区的回车,否则,str2只能接收到一个回车符。
5&&&&&&&&scanf(&%s&,str1);
(gdb) p str1
$1 = &abcdef\000aa&
(gdb) p str2
$2 = &\000bbbbbbbb&
[ 本帖最后由 pauljames 于
06:47 编辑 ]
经常不在线不能及时回复短消息,如有c/单片机/运动控制/数据采集等方面的项目难题可加qq。
来 自:广东潮州
等 级:小飞侠
帖 子:1182
专家分:2784
悲剧,发错人了
[ 本帖最后由 A 于
07:10 编辑 ]
一步一个脚印...............................默默地前进.....
诚邀乐于解答c菜鸟问题,的热心网友加入,&&QQ群
等 级:青峰侠
帖 子:358
专家分:1852
回复 3楼 pauljames
那如果我想输入一串带空格的字符,比如说&I am a stdudent&,那就不能用scanf来接收了,而必须用gets或fgets了?
来 自:山东
等 级:蝙蝠侠
帖 子:319
专家分:807
试了一下,应该是这样
等 级:论坛游民
帖 子:40
专家分:70
&&得分:10&
gets函数可以一次接收一行输入串,其中可以有空格,也就是说空格可以做为字符串的一部分输入.
而scanf函数接收的字符串不会含有空格,即遇到字空格时,认为字符串输入结束,也就是说空格是scanf默认的结束符号。
版权所有,并保留所有权利。
Powered by , Processed in 0.063429 second(s), 8 queries.
Copyright&, BCCN.NET, All Rights Reserved字符编码常识及问题解析 - 文章 - 伯乐在线
& 字符编码常识及问题解析
在面试的笔试题里出了一道开放性的题:请简述Unicode与UTF-8之间的关系。一道看似简单的题,能给出满意答案的却寥寥无几 ,确实挺失望的。所以今天就结合我以前做过的一个关于字符编码的分享,总结一些与字符编码相关的知识和问题。如果你这方面的知识已经掌握的足够了,可以忽略这篇文字。但如果你没法很好的回答我上面的面试题,或经常被乱码的问题所困扰,还是不妨一读。
1.位和字节
说起编码,我们必须从最基础的说起,位和字节(别觉得这个过于简单不值一说,我还真见过很多个不能区分这两者的程序员)。位(bit)是指计算机里存放的二进制值(0/1),而8个位组合成的“位串”称为一个字节,容易算出,8个位的组合有256( 28 )个组合方式,其取值范围是“11111”,常用十六进制来表示。比如“”就是一个字节,其对应的十六进制值为“0x41”。
而我们通常所讲的字符编码,就是指定义一套规则,将真实世界里的字母/字符与计算机的二进制序列进行相互转化。如我们可以针对上面的字节定义如下的转换规则:
x41)&-& 65 &-& 'A'
(0x41)&-& 65 &-& 'A'
即用字位序“”来表示字母’A’。
2.拉丁字符
拉丁字符是当今世界使用最广泛的符号了。通常我们说的拉丁字母,指的的是基础拉丁字母,即指常见的”ABCD“等26个英文字母,这些字母与英语中一些常见的符号(如数字,标点符号)称为基础拉丁字符,这些基础拉丁字符在使用英语的国家广为流行,当然在中国,也被用来当作汉语拼音使用。在欧洲其它一些非英语国家,为满足其语言需要,在基础拉丁字符的基础上,加上一些连字符,变音字符(如’?’),形成了派生拉丁字母,其表示的字符范围在各种语言有所不同,而完整意义上的拉丁字符是指这些变体字符与基础拉丁字符的全集。是比基础拉丁字符集大很多的一个集合。
前文提到,字符编码是一套规则。既然是规则,就必须有标准。下面我就仔细说说常见的字符编码标准。
1.拉丁编码
ASCII的全称是American Standard Code for Information Interchange(美国信息交换标准代码)。顾名思义,这是现代计算机的发明国美国人设计的标准,而美国是一个英语国家,他们设定的ASCII编码也只支持基础拉丁字符。ASCII的设计也很简单,用一个字节(8个位)来表示一个字符,并保证最高位的取值永远为’0’。即表示字符含义的位数为7位,不难算出其可表达字符数为27 =128个。这128个字符包括95个可打印的字符(涵盖了26个英文字母的大小写以及英文标点符号能)与33个控制字符(不可打印字符)。例如下表,就是几个简单的规则对应:
可打印字符
可打印字符
前面说到了,ASCII是美国人设计的,只能支持基础拉丁字符,而当计算机发展到欧洲,欧洲其它不只是用的基础拉丁字符的国家(即用更大的派生拉丁字符集)该怎么办呢?
当然,最简单的办法就是将美国人没有用到的第8位也用上就好了,这样能表达的字符个数就达到了28 =256个,相比较原来,增长了一倍, 这个编码规则也常被称为EASCII。EASCII基本解决了整个西欧的字符编码问题。但是对于欧洲其它地方如北欧,东欧地区,256个字符还是不够用,如是出现了ISO 8859,为解决256个字符不够用的问题,ISO 8859采取的不再是单个独立的编码规则,而是由一系列的字符集(共15个)所组成,分别称为ISO 8859-n(n=1,2,3…11,13…16,没有12)。其每个字符集对应不同的语言,如ISO 8859-1对应西欧语言,ISO 8859-2对应中欧语言等。其中大家所熟悉的Latin-1就是ISO 8859-1的别名,它表示整个西欧的字符集范围。 需要注意的一点的是,ISO 8859-n与ASCII是兼容的,即其x00)-x7f)范围段与ASCII保持一致,而x80)-xFF)范围段被扩展用到不同的字符集。
2.中文编码
以上我们接触到的拉丁编码,都是单字节编码,即用一个字节来对应一个字符。但这一规则对于其它字符集更大的语言来说,并不适应,比如中文,而是出现了用多个字节表示一个字符的编码规则。常见的中文GB2312(国家简体中文字符集)就是用两个字节来表示一个汉字(注意是表示一个汉字,对于拉丁字母,GB2312还是是用一个字节来表示以兼容ASCII)。我们用下表来说明各中文编码之间的规则和兼容性。
对于中文编码,其规则实现上是很简单的,一般都是简单的字符查表即可,重要的是要注意其相互之间的兼容性问题。如如果选择BIG5字符集编码,就不能很好的兼容GB2312,当做繁转简时有可能导致个别字的冲突与不一致,但是GBK与GB2312之间就不存在这样的问题。
以上可以看到,针对不同的语言采用不同的编码,有可能导致冲突与不兼容性,如果我们打开一份字节序文件,如果不知道其编码规则,就无法正确解析其语义,这也是产生乱码的根本原因。有没有一种规则是全世界字符统一的呢?当然有,Unicode就是一种。为了能独立表示世界上所有的字符,Unicode采用4个字节表示一个字符,这样理论上Unicode能表示的字符数就达到了231 =
= 21 亿左右个字符,完全可以涵盖世界上一切语言所用的符号。我们以汉字”微信“两字举例说明:
微 &-& \u5fae &-& 11
信 &-& \u4fe1 &-& 11
容易从上面的例子里看出,Unicode对所有的字符编码均需要四个字节,而这对于拉丁字母或汉字来说是浪费的,其前面三个或两个字节均是0,这对信息存储来说是极大的浪费。另外一个问题就是,如何区分Unicode与其它编码这也是一个问题,比如计算机怎么知道四个字节表示一个Unicode中的字符,还是分别表示四个ASCII的字符呢?
以上两个问题,困扰着Unicode,让Unicode的推广上一直面临着困难。直至UTF-8作为Unicode的一种实现后,部分问题得到解决,才得以完成推广使用。说到此,我们可以回答文章一开始提出的问题了,UTF-8是Unicode的一种实现方式,而Unicode是一个统一标准规范,Unicode的实现方式除了UTF-8还有其它的,比如UTF-16等。
话说当初大牛Ben Thomson吃饭时,在一张餐巾纸上,设计出了UTF-8,然后回到房间,实现了第一版的UTF-8。关于UTF-8的基本规则,其实简单来说就两条(来自阮一峰老师的总结):
规则1:对于单字节字符,字节的第一位为0,后7位为这个符号的Unicode码,所以对于拉丁字母,UTF-8与ASCII码是一致的。
规则2:对于n字节(n&1)的字符,第一个字节前n位都设为1,第n+1位为0,后面字节的前两位一律设为10,剩下没有提及的位,全部为这个符号的Unicode编码。
通过,根据以上规则,可以建立一个Unicode取值范围与UTF-8字节序表示的对应关系,如下表,
举例来说,’微’的Unicode是’\u5fae’,二进制表示是”11 “,其取值就位于’00 FFFF’之间,所以其UTF-8编码为’11100101 10111110 10101110’ (加粗部分为固定编码内容)。
通过以上简单规则,UTF-8采取变字节的方式,解决了我们前文提到的关于Unicode的两大问题。同时,作为中文使用者需要注意的一点是Unicode(UTF-8)与GBK,GB2312这些汉字编码规则是完全不兼容的,也就是说这两者之间不能通过任何算法来进行转换,如需转换,一般通过GBK查表的方式来进行。
常见问题及解答
1.windows Notepad中的编码ANSI保存选项,代表什么含义?
ANSI是windows的默认的编码方式,对于英文文件是ASCII编码,对于简体中文文件是GB2312编码(只针对Windows简体中文版,如果是繁体中文版会采用Big5码)。所以,如果将一个UTF-8编码的文件,另存为ANSI的方式,对于中文部分会产生乱码。
2.什么是UTF-8的BOM?
BOM的全称是Byte Order Mark,BOM是微软给UTF-8编码加上的,用于标识文件使用的是UTF-8编码,即在UTF-8编码的文件起始位置,加入三个字节“EE BB BF”。这是微软特有的,标准并不推荐包含BOM的方式。采用加BOM的UTF-8编码文件,对于一些只支持标准UTF-8编码的环境,可能导致问题。比如,在Go语言编程中,对于包含BOM的代码文件,会导致编译出错。详细可见我的。
3.为什么数据库Latin1字符集(单字节)可以存储中文呢?
其实不管需要使用几个字节来表示一个字符,但最小的存储单位都是字节,所以,只要能保证传输和存储的字节顺序不会乱即可。作为数据库,只是作为存储的使用的话,只要能保证存储的顺序与写入的顺序一致,然后再按相同的字节顺序读出即可,翻译成语义字符的任务交给应用程序。比如’微’的UTF-8编码是’0xE5 0xBE 0xAE’,那数据库也存储’0xE5 0xBE 0xAE’三个字节,其它应用按顺序从数据库读取,再按UTF-8编码进行展现。这当然是一个看似完美的方案,但是只要写入,存储,读取过程中岔出任何别的编码,都可能导致乱码。
4.Mysql数据库中多个字符集变量(其它数据库其实也类似),它们之间分别是什么关系?
我们分别解释:
character_set_client:客户端来源的数据使用的字符集,用于客户端显式告诉客户端所发送的语句中的的字符编码。
character_set_connection:连接层的字符编码,mysql一般用character_set_connection将客户端的字符转换为连接层表示的字符。
character_set_results:查询结果从数据库读出后,将转换为character_set_results返回给前端。
而我们常见的解决乱码问题的操作:
mysql_query('SET NAMES GBK')
mysql_query('SET NAMES GBK')
其相当于将以上三个字符集统一全部设置为GBK,这三者一致时,一般就解决了乱码问题。
character_set_database:当前选中数据库的默认字符集,如当create table时没有指定字符集,将默认选择该字符集。
character_set_database已经character_set_system,一般用于数据库系统内部的一些字符编码,处理数据乱码问题时,我们基本可以忽略。
5.什么情况下,表示信息丢失?
对于mysql数据库,我们可以通过hex(colname)函数(其它数据库也有类似的函数,一些文本文件编辑器也具有这个功能),查看实际存储的字节内容,如:
通过查看存储的字节序,我们可以从根本上了解存储的内容是什么编码了。而当发现存储的内容全部是’3F’时,就表明存储的内容由于编码问题,信息已经丢失了,无法再找回。
之所以出现这种信息丢失的情况,一般是将不能相互转换的字符集之间做了转换,比如我们在前文说到,UTF-8只能一个个字节地变成Latin-1,但是根本不能转换的,因为两者之间没有转换规则,Unicode的字符对应范围也根本不在Latin-1范围内,所以只能用’?(0x3F)’代替了。
本文从基础知识与实际中碰到的问题上,解析了字符编码相关内容。而之所以要从头介绍字符编码的基础知识,是为了更好的从原理上了解与解决日常碰到的编码问题,只有从根本上了解了不同字符集的规则及其之间的关系与兼容性,才能更好的解决碰到的乱码问题,也能避免由于程序中不正确的编码转换导致的信息丢失问题。
可能感兴趣的话题
关于伯乐在线博客
在这个信息爆炸的时代,人们已然被大量、快速并且简短的信息所包围。然而,我们相信:过多“快餐”式的阅读只会令人“虚胖”,缺乏实质的内涵。伯乐在线内容团队正试图以我们微薄的力量,把优秀的原创文章和译文分享给读者,为“快餐”添加一些“营养”元素。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2017 伯乐在线初学 C 的指针和字符串,使用时出现一些问题,还请指点一下 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
已注册用户请 &
初学 C 的指针和字符串,使用时出现一些问题,还请指点一下
14:23:25 +08:00 · 1416 次点击
我的代码是要处理这样的字符串
$GPRMC,,A,,N,,E,10.05,324.27,150706,,,A*50
程序要读入多行这样的字符串,依据&,&分割字符串
然后判断0号字段是否为&$GPRMC&,2号字段是否为“A&,并且验证校验和,即从字符'$'到''中间的所有字符的异或为''后面的两个字符(这两个字符为十六进制表示)
最后将最后一个符合要求的字符串的1号字段前6个字符(即 uc t时间)转化为 bjt 时间
在最后一步,我遇到这样一个问题,我开了一个大小为7的字符数组,将转化后的 bjt 时间用 strcpy()填充到字符数组中却得到乱码,请问是怎么回事呢?
#include &stdio.h&
#include &string.h&
#include &stdlib.h&
char* str_sub( char str[], int start, int end );
void str_split( char* words[], char str[], char* delim );
int chk_sum( char sen[] );
int hex_to_dec( char *s );
int chk_val( char sen[] );
void print_bjt( char uct[] );
int is_vaild( char *words[], int chksum, int chkval );
int main()
/*char str[] = &$GPRMC,,A,,N,,E,10.05,324.27,150706,,,A*50&;*/
char sen[255];
char uct[7];
scanf ( &%s&, sen );
while ( strcmp( sen, &END& ) != 0 )
char *words[17];
int chksum = chk_sum( sen );
int chkval = chk_val( sen );
printf ( &chksum=%d chkval=%d\n&, chksum, chkval );
str_split( words, sen, &,& );
printf ( &word[1]=%s\n&, words[0] );
printf ( &word[2]=%s\n&, words[1] );
printf ( &%s\n&, sen );
if ( is_vaild( words, chksum, chkval ) == 1 )
printf (&%s\n&, str_sub( words[1], 0, 6 ) );
strncpy( uct, str_sub( words[1], 0, 6 ), 6 );
printf (&%s\n&, uct );
scanf ( &%s&, sen );
printf (&%s\n&, uct );
print_bjt( uct );
char* str_sub( char str[], int start, int end )
char new_str[end - start + 1];
char *result =
for ( int i = start, j = 0; i & end - start; i++, j++ )
new_str[j] = str[i];
result[end-start] = '\0';
return result;
void str_split( char* words[], char str[], char* delim )
int i = 0;
char *buf = str;
while ( (words[i] = strtok( buf, delim ) ) != NULL )
buf = NULL;
int chk_sum( char sen[] )
char *p = NULL;
p = strchr ( sen, '$' ) + 1;
int xor = *p++;
while ( *p != '*' )
xor ^= *p;
xor %= 65536;
return xor;
int chk_val( char sen[] )
char *p = NULL;
p = strchr( sen, '*' ) + 1;
int checkval = hex_to_dec( p );
return checkval;
int hex_to_dec( char *s )
int n = 0;
int i = 0;
for (i = 0; s[i] != '\0'; i++)
if (s[i] &= '0' && s[i] &= '9')
n = n * 16 + s[i] - '0';
if (s[i] &= 'a' && s[i] &= 'f')
n = n * 16 + s[i] - 'a' + 10;
if (s[i] &= 'A' && s[i] &= 'F')
n = n * 16 + s[i] - 'A' + 10;
int is_vaild( char *words[], int chksum, int chkval )
int ret = 0;
if ( strcmp( words[0], &$GPRMC& ) == 0 &&
strcmp( words[2], &A& ) == 0 &&
chksum == chkval )
return ret;
void print_bjt( char uct[] )
int uct_h1 = ( uct[0] - '0' ) * 10;
int uct_h2 = ( uct[1] - '0' );
int uct_hh = uct_h1 + uct_h2;
int bjt_hh = ( uct_hh + 8 ) % 24;
printf ( &%2d:%c%c:%c%c&, bjt_hh, uct[2], uct[3], uct[4], uct[5] );
23 回复 &| &直到
15:30:35 +08:00
& & 16:37:58 +08:00
虽然我没有看你的代码,不过下次好歹程序运行到你出错那前面打个断点,我看你已经输出%s成功了是吧(printf (&%s\n&, uct );
),那么你肯定没搞清楚字符串转换为整数是什么意思,用atoi函数。把数据类型弄一样了再运算。
不然你的字符'3'*10是什么意思 程序必然将'3'先转化为ascii码再做乘法,跟你想要达到效果是大相径庭的。简单的来说9+1=10. '9'+1=多少呢? 呵呵明白了吧
& & 19:30:11 +08:00
沒編過
char new_str[end - start + 1];
你如果要申請變長char 數組,要用new
然後記得用完刪掉
& & 19:45:37 +08:00
你的另一個問題是strncpy的使用,你複製一個長度7的字串(0-6),但是只複製前6個沒有/0,所以你會看到亂碼
我簡單改了一下你的代碼,這份代碼可以運行但不代表正確(比如我new 出來數組沒刪),只是說明問題在哪裡
指針的問題你還要再研究,寫太多就長了
#include &stdio.h&
#include &string.h&
#include &stdlib.h&
char* str_sub( char str[], int start, int end );
void str_split( char* words[], char str[], char* delim );
int chk_sum( char sen[] );
int hex_to_dec( char *s );
int chk_val( char sen[] );
void print_bjt( char uct[] );
int is_vaild( char *words[], int chksum, int chkval );
int main()
{
char str[] = &$GPRMC,,A,,N,,E,10.05,324.27,150706,,,A*50&;
char sen[255];
char uct[7];
memcpy(sen, str, sizeof str);
//scanf ( &%s&, sen );
while ( strcmp( sen, &END& ) != 0 )
char *words[17];
int chksum = chk_sum( sen );
int chkval = chk_val( sen );
printf ( &chksum=%d chkval=%d\n&, chksum, chkval );
str_split( words, sen, &,& );
printf ( &word[1]=%s\n&, words[0] );
printf ( &word[2]=%s\n&, words[1] );
printf ( &%s\n&, sen );
if ( is_vaild( words, chksum, chkval ) == 1 )
printf (&%s\n&, str_sub( words[1], 0, 6 ) );
strncpy( uct, str_sub( words[1], 0, 6 ), 7 );
printf (&%s\n&, uct );
scanf ( &%s&, sen );
printf (&%s\n&, uct );
print_bjt( uct );
return 0;
}
char* str_sub( char str[], int start, int end )
{
char* new_str = new char[end - start + 1];
char *result =
for ( int i = start, j = 0; i & end - i++, j++ )
new_str[j] = str[i];
result[end-start] = '\0';
void str_split( char* words[], char str[], char* delim )
{
int i = 0;
char *buf =
while ( (words[i] = strtok( buf, delim ) ) != NULL )
buf = NULL;
int chk_sum( char sen[] )
{
char *p = NULL;
p = strchr ( sen, '$' ) + 1;
int xor = *p++;
while ( *p != '*' )
xor ^= *p;
xor %= 65536;
int chk_val( char sen[] )
{
char *p = NULL;
p = strchr( sen, '*' ) + 1;
int checkval = hex_to_dec( p );
int hex_to_dec( char *s )
{
int n = 0;
int i = 0;
for (i = 0; s[i] != '\0'; i++)
if (s[i] &= '0' && s[i] &= '9')
n = n * 16 + s[i] - '0';
if (s[i] &= 'a' && s[i] &= 'f')
n = n * 16 + s[i] - 'a' + 10;
if (s[i] &= 'A' && s[i] &= 'F')
n = n * 16 + s[i] - 'A' + 10;
int is_vaild( char *words[], int chksum, int chkval )
{
int ret = 0;
if ( strcmp( words[0], &$GPRMC& ) == 0 &&
strcmp( words[2], &A& ) == 0 &&
chksum == chkval )
void print_bjt( char uct[] )
{
int uct_h1 = ( uct[0] - '0' ) * 10;
int uct_h2 = ( uct[1] - '0' );
int uct_hh = uct_h1 + uct_h2;
int bjt_hh = ( uct_hh + 8 ) % 24;
printf ( &%2d:%c%c:%c%c&, bjt_hh, uct[2], uct[3], uct[4], uct[5] );
}
& & 20:24:41 +08:00
@ 就是输出 uct 是一个乱码,相不明白怎么会是乱码呢?
& & 20:27:26 +08:00
@ 我试着添加代码
strncpy( uct, str_sub( words[1], 0, 6 ), 6 );
uct[6] = '\0';
uct 输出依旧是乱码
& & 21:55:55 +08:00
我这里试了下跑出来是正常结果,没乱码。
[root@localhost test]# gcc test.c -std=c99
[root@localhost test]# ./a.out
$GPRMC,,A,,N,,E,10.05,324.27,150706,,,A*50
chksum=80 chkval=80
word[1]=$GPRMC
word[2]=
$GPRMC
024813
024813
END
024813
10:48:13[root@localhost test]#
& & 22:10:20 +08:00
@ 奇怪,zsh shell 和 bash shell 都试了,还是乱码
? ~ gcc test.c -std=c99
? ~ ./a.out
$GPRMC,,A,,N,,E,10.05,324.27,150706,,,A*50
chksum=80 chkval=80
word[1]=$GPRMC
word[2]=
$GPRMC
024813
?X?
-1:?X:??
& & 22:57:04 +08:00
uct 用之前清空试试?
& & 23:55:11 +08:00
memset(uct, 0, sizeof(uct));
吗?
& & 00:43:23 +08:00 via Android
。。。为毛学完C表示看这个还是不懂。。。
看来我连初学都不算啊。。。
& & 00:54:19 +08:00
@ 这是c99的code,需要在gcc -std=C99编译。
LZ我给你提个醒, 这算是C的一个坑。在函数内部使用数组,出了函数,这个数组会被释放掉的。必须malloc或是使用static变量,这里用了变长,不能用static了,只能malloc了。
贴个代码,你感受下:
#include &stdio.h&
char* wrong_fun(){
char local_array[]=&&;
char *will_be_delete = local_
return will_be_
}
int main(){
printf(&%s\n&, wrong_fun());
}
再试试:static char local_array[]=&&;
@
& & 00:59:14 +08:00
跑下题,我觉得这个问题可以试试用python解决= =
& & 07:11:00 +08:00
一点也不奇怪。楼上说的很清楚了,你取了一个local variable的地址传回去了,函数返回后local variable都被释放了,这个地址就变成幽灵了,它指向的地址是一个薛定谔的猫,有两种状态,老值可能还存在,也可能不存在了。这个传回的指针实际上是非法的。你可能能得到正确的结果,但多半得不到正确的结果。不信你多运行几次可能显示都不一样。
建议找一本好的C语言教材扎扎实实从头学一下。另外,能用C++就不要再用C了,C的内存管理是个大坑。用现代C++能避免很多问题。顺便说一下这种看似随机的错误,多半是非法指针搞的。
& & 07:18:48 +08:00
楼上还有混合C和C++的。在C99下用malloc的话,你的那行
char new_str[end - start + 1];
改成
char *new_str = malloc((end - start + 1) * sizeof(char));
就没乱码了。然后在调用这个函数之后按理说还应该free。这是最小化改动现有代码的方法,只是太不优雅了。
& & 09:37:10 +08:00
@ 没,是我写的一点都不好。
我简单介绍一下我的代码。
char* str_sub( char str[], int start, int end );
切割出传入的字符串,从下标为 start 到 end为止。
思路是,创建一个 end-start+1 长度的字符数组,循环字符串,将字符串中下标为 start 到 end 的字符 传入到数组中,最后返回这个数组,即切割好的字符串
void str_split( char* words[], char str[], char* delim );
将字符串根据指定的字符切割成,字符串数组。
这里我需要将题目中传入的句子根据逗号切割成字段,就用到它。它的实现,用到 strtok() 切割字符串,用法我是参考文档的,我做的就是将切割好的字符串,存到字符串数组中,字符串数组我定义为 char ** 不知道合不合适。
int chk_sum( char sen[] );
计算校验和
根据题目要求计算 '$'到'*'的所有字符的异或值
int hex_to_dec( char *s );
将十六进制转化为十进制
int chk_val( char sen[] );
得到字符串最后一个字段'*'字符后面的两个数字
void print_bjt( char uct[] );
根据传入的 uct 字符串,打印 bjt ,格式为 hh:mm:ss
int is_vaild( char *words[], int chksum, int chkval );
根据题目要求验证,0号字段是否为&$GPRMC&,2号字段是否为“A&,并且验证校验和,即从字符'$'到''中间的所有字符的异或为''后面的两个字符
& & 09:45:12 +08:00
楼上诸位说得对,问题出在str_sub()函数,result指针指向的new_str[]数组位于栈区,函数执行完毕就被释放了,所以得到的结果不可预料,应该改为malloc动态分配。
& & 09:45:36 +08:00
@ 一开始我用 Java 实现并且通过,只是课程要求必须用 C 实现,准备改写为 C 时发现,C 中并没有 Java的处理字符串的函数,然后自己写函数实现,但是指针字符串没过关,就遇到现在这种情况了。C 处理字符串感觉没有 Java 方便。
& & 09:56:09 +08:00
@ 谢谢了,学会了 malloc 的用法。发现 C 中的指针真的很难,昨晚我在调式代码找错误时,发现如果输入的字符串不是题目的格式,比如 ”dasdas,dasdas,asdasd&, 程序就提示
terminated by signal SIGSEGV (Address boundary error)
& & 12:12:50 +08:00
@ 我代碼有寫,你比下差異
strncpy( uct, str_sub( words[1], 0, 6 ), 7 );
& & 12:25:32 +08:00
@ c99可以這樣寫?
char new_str[end - start + 1];
& & 12:28:20 +08:00
@ 可以。还有for (int i = 1; i & 10; i++)
& & 13:38:52 +08:00
@ 之前没仔细看你的代码。现在发现你没必要自己写一个str_sub。你想想,strncpy不就是str_sub吗?你把
printf (&%s\n&, str_sub( words[1], 0, 6 ) );
strncpy( uct, str_sub( words[1], 0, 6 ), 6 );
这两行换成
strncpy( uct, words[1], 6 );
一样能跑通,还没有你出现的内存的问题。
另外楼上有提到,你的uct的最后一个字符串结束符\0没有处理。最好的办法其实是在初始化uct时把uct[6]初始化为0。数组在创建时是不自动初始化的,里边的值可能是任意值,只不过程序刚开始很可能是0,但是不初始化是不安全的。应该养成好习惯。万一不是0,你的uct就可能出问题了。
& & 15:30:35 +08:00
@ 所以可以申請變長數組喔
& · & 2034 人在线 & 最高记录 2466 & · &
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.7.5 · 29ms · UTC 07:01 · PVG 15:01 · LAX 00:01 · JFK 03:01? Do have faith in what you're doing.}

我要回帖

更多关于 字符串长度 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信