C语言c语言 数字转字符串问题

(window.slotbydup=window.slotbydup || []).push({
id: '2081942',
container: s,
size: '1000,60',
display: 'inlay-fix'今天再看面试题时 出现了一个字符串左右移动循环的问题,看了一遍还没有弄懂,就发了点时间来看了一下字符数组与字符指针的问题,最终还是得到解决,呵呵,只要肯发功夫,还是会有收获的
& 例如:有一组char的字符串:abcdefghijk
。你要循环左移3位变成ijkabcdefgh(也有写出ijkabcdefghi);或右移三位变成defghijkabc(也有写成cdefghijkabc);
&& 首先我们来解决字符串循环右移的问题:
方法一:利用已有的字符串函数。
#include&stdio.h&
#include&string.h&
void rightloop(char *a, int n);
char a[100];&&
printf("请输入要循环的字符串:\n");
scanf("%s",a);
printf("请输入要循环字符串的位数:\n");
scanf("%d",&n);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&
\\以上代码也可以直接赋初值,我考虑的是一般情况\\
void rightloop(a,n);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& \\本例以a[]="abcdefghijk",
n=3为例讲解\\
printf("输出循环右移的字符串:%s\n",a);
void rightloop(char *a, int n)
char b[100];&&&& \\数组b要做的够大即可\\
m=strlen(a)-n;&&&&&&&&&&& &&
\\求出除去要循环右移之后剩下的字符的个数\\
strcpy(b,a+n);&&&&&&&&&&& \\
a+n,a代表a[0]的地址再加上n,表示要把a[n]之后的字符串(即那些不用循环右移的字符,共有m个)复制到数组b中。这时b[]="defghijk"。
strcpy(b+m,a);&&&&&&&&&&&&&&&&& \\ b+m,
因为上面已经把没有循环的m个字符赋给了b,所以b[m]之前的不能在赋值了,只能把a的全部字符串赋给b[m]之后的空间了。这时b[]="defghijkabcdefghijk"。\\
*(b+strlen(a))='\0';&&&&&&&&&&&&&& \\这里是问题的关键,要根据a字符串的长度来舍弃b数组中多余的字符串,并给数
组b加结束符。这时b[]="defghijkabc";\\
strcpy(a,b);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& \\把数组b中调整好的字符串重新赋给数组a。\\
方法二:就是用简单的c语句;
#include&stdio.h&
void rightloop(char , int )
char a[100];&&
printf("请输入要循环的字符串:\n");
scanf("%s",a);
printf("请输入要循环字符串的位数:\n");
scanf("%d",&n);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&
\\以上代码也可以直接赋初值,我考虑的是一般情况\\
void rightloop(a,n);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& \\本例以a[]="abcdefghijk",
n=3为例讲解\\
printf("输出循环右移的字符串:%s\n",a);
void rightloop(char a[ ], int n)
&&&&&& int i=0,j=0,k=0;
&&&&&&& char b[100];
while(a[i]!='\0')
&&&&&&& { i++; }&&&& \\这里用i来计算数组a中字符串的大小;\\
while(a[n]!='\0')
&&&& b[j]=a[n]; j++; n++;
}& \\这里是把不需要循环右移的字符串赋值到数组b中;b[
]="defghijk"。\\
while(a[k]!='\0')
&&& b[j]=a[k]; j++; k++;
}&&&&&& &&&&&&&&& \\因为上一个while循环中,数组b已经赋值到b[j]了。所以这里直接从b[j]开始把数组a中的字符串全部赋值到数组b[j]以后的空间中;b
[ ]="defghijkabcdefghijk";\\
b[i]='\0';&&&&& \\通过用数组a中字符串的长度i来调整数组b的长度,删去数组b中多余的字符串
,b[]="defghijklabc"。
for(i=0;b[i]!='\0';i++)
&&&&&&&&&& { a[i]=b[i]; }&&&&&&&&&&&&&&&&& \\把数组b中调整好的字符串重新赋给数组a。\\
再次我们来解决字符串循环左移的问题
方法一:调用已经有的字符串函数。
#include&stdio.h&
#include&string.h&
void leftloop(char *a, int n);
char a[100];&&
printf("请输入要循环的字符串:\n");
scanf("%s",a);
printf("请输入要循环字符串的位数:\n");
scanf("%d",&n);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& \\以上代码也可以直接赋初值,我考虑的是一般情况\\
void leftloop(a,n);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& \\本例以a[]="abcdefghijk",
n=3为例讲解\\
printf("输出已经循环左移的字符串:%s\n",a);
void leftloop(char*a,int n)
{char b[100];&&&&& \\数组b要做的够大即可\\
m=strlen(a)-n;&&&&&&&&&&&&& \\求出除去要循环右移之后剩下的字符的个数\\
strcpy(b,a+m);&&&&&&&&&&& \\
a+m,a代表a[0]的地址再加上m,表示要把a[m]之后的字符串(即那些需要循环左移的字符,共有n个)复制到数组b中。这时b[]="ijk"。
strcpy(b+n,a);&&&&&&&&&&&&&&&&& \\ b+n,
因为上面已经把需要循环的n个字符赋给了b,所以b[n]之前的不能在赋值了,只能把a的全部字符串赋给b[n]之后的空间了。这时b[]="ijkabcdefghijk"。\\
*(b+strlen(a))='\0';&&&&&&&&&&&&& \\这里是问题的关键,要根据a字符串的长度来舍弃b数组中多余的字符串,并给数组b加结束符。这时b[]="ijkabcdefgh";\\
strcpy(a,b);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& \\把数组b中调整好的字符串重新赋给数组a。\\
方法二:就是用简单的c语句;#include&stdio.h&
void leftloop(char , int )
char a[100];&&
printf("请输入要循环的字符串:\n");
scanf("%s",a);
printf("请输入要循环字符串的位数:\n");
scanf("%d",&n);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&
\\以上代码也可以直接赋初值,我考虑的是一般情况\\
void leftloop(a,n);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& \\本例以a[]="abcdefghijk",
n=3为例讲解\\
printf("输出已经循环左移的字符串:%s\n",a);
void leftloop(char a[ ], int n)
&&&&&& int i=0,j=0,k;
&&&&&&& char b[100];
while(a[i]!='\0')
&&&&&&& { i++; }&&&& \\这里用i来计算数组a中字符串的大小;\\
k=m=i-n;&&&&&&&&& \\计算出前面有多少个字符不用移动\\
while(a[k]!='\0')
&&&& b[j]=a[k]; j++; k++;
}& \\因为这时k=i-m,a[k]表示需要循环移动的第一个字符,这里是把需要循环右移的字符串赋值到数组b中;b[
]="ijk"。\\
b[j]='\0';
m--;k--;&&&& \\因为要用m调节下面的循环但是要从0开始所以比实际的多了一次;k--是为了要留着数组a中的结束符,不出现乱码;\\
while(m&=0)
&&& a[k]=a[m]; m--; k--;
}&&&&&& &&&&&&&&&& \\
原来a[k]=&abcdefghijk",a[m]="abcdefgh",赋值之后a[k]="abcabcdefgh";\\
for(i=0;b[i]!='\0';i++)
&&&&&&&&&& { a[i]=b[i]; }&&&&&& \\把数组b中调整好的字符串重新赋给数组a。b[i]="ijk";a[i]="abcabcdefgh"。赋值之后a[i]="j\\
阅读(...) 评论()在将各种类型的数据构造成字符串时,sprintf 的强大功能很少会让你失望。由于sprintf 跟printf 在用法上几乎一样,只是打印的目的地不同而已,前者打印到字符串中,后者则直接在命令行上输出。这也导致sprintf 比printf 有用得多。
sprintf 是个变参函数,定义如下:
int sprintf( char *buffer, const char *format [, argument] ... );
除了前两个参数类型固定外,后面可以接任意多个参数。而它的精华,显然就在第二个参数:
格式化字符串上。
printf 和sprintf 都使用格式化字符串来指定串的格式,在格式串内部使用一些以&%&开头的格式说明符(format specifications)来占据一个位置,在后边的变参列表中提供相应的变量,最终函数就会用相应位置的变量来替代那个说明符,产生一个调用者想要 的字符串。
格式化数字字符串
sprintf 最常见的应用之一莫过于把整数打印到字符串中,所以,spritnf 在大多数场合可以替代
//把整数123 打印成一个字符串保存在s 中。
sprintf(s, &%d&, 123); //产生&123&
可以指定宽度,不足的左边补空格:
sprintf(s, &%8d%8d&, 123, 4567); //产生:& 123 4567&
当然也可以左对齐:
sprintf(s, &%-8d%8d&, 123, 4567); //产生:&123 4567&
也可以按照16 进制打印:
sprintf(s, &%8x&, 4567); //小写16 进制,宽度占8 个位置,右对齐
sprintf(s, &%-8X&, 4568); //大写16 进制,宽度占8 个位置,左对齐
这样,一个整数的16 进制字符串就很容易得到,但我们在打印16 进制内容时,通常想要一种左边补0 的等宽格式,那该怎么做呢?很简单,在表示宽度的数字前面加个0 就可以了。
sprintf(s, &%08X&, 4567); //产生:&&
上面以&%d&进行的10 进制打印同样也可以使用这种左边补0 的方式。
这里要注意一个符号扩展的问题:比如,假如我们想打印短整数(short)-1 的内存16 进制表示形式,在Win32 平台上,一个short 型占2 个字节,所以我们自然希望用4 个16 进制数字来打印它:
short si = -1;
sprintf(s, &%04X&, si);
产 生&FFFFFFFF&,怎么回事?因为spritnf 是个变参函数,除了前面两个参数之外,后面的参数都不是类型安全的,函数更没有办法仅仅通过一个&%X&就能得知当初函数调用前参数压栈时被压进来的到底 是个4 字节的整数还是个2 字节的短整数,所以采取了统一4 字节的处理方式,导致参数压栈时做了符号扩展,扩展成了32 位的整数-1,打印时4 个位置不够了,就把32 位整数-1 的8 位16 进制都打印出来了。
如果你想看si 的本来面目,那么就应该让编译器做0 扩展而不是符号扩展(扩展时二进制左边补0 而不是补符号位):
sprintf(s, &%04X&, (unsigned short)si);
就可以了。或者:
unsigned short si = -1;
sprintf(s, &%04X&, si);
sprintf 和printf 还可以按8 进制打印整数字符串,使用&%o&。注意8 进制和16 进制都不会打
印出负数,都是无符号的,实际上也就是变量的内部编码的直接的16 进制或8 进制表示。
控制浮点数打印格式
浮点数的打印和格式控制是sprintf 的又一大常用功能,浮点数使用格式符&%f&控制,默认保
留小数点后6 位数字,比如:
sprintf(s, &%f&, 3.1415926); //产生&3.141593&
但有时我们希望自己控制打印的宽度和小数位数,这时就应该使用:&%m.nf&格式,其中m 表
示打印的宽度,n 表示小数点后的位数。比如:
sprintf(s, &%10.3f&, 3.1415626); //产生:& 3.142&
sprintf(s, &%-10.3f&, 3.1415626); //产生:&3.142 &
sprintf(s, &%.3f&, 3.1415626); //不指定总宽度,产生:&3.142&
注意一个问题,你猜
int i = 100;
sprintf(s, &%.2f&, i);
会打出什么东东来?&100.00&?对吗?自己试试就知道了,同时也试试下面这个:
sprintf(s, &%.2f&, (double)i);
第 一个打出来的肯定不是正确结果,原因跟前面提到的一样,参数压栈时调用者并不知道跟i相对应的格式控制符是个&%f&。而函数执行时函数本身则并不知道当 年被压入栈里的是个整数,于是可怜的保存整数i 的那4 个字节就被不由分说地强行作为浮点数格式来解释了,整个乱套了。不过,如果有人有兴趣使用手工编码一个浮点数,那么倒可以使用这种方法来检验一下你手工编 排的结果是否正确。
字符/Ascii 码对照
我们知道,在C/C++语言中,char 也是一种普通的scalable 类型,除了字长之外,它与short,
int,long 这些类型没有本质区别,只不过被大家习惯用来表示字符和字符串而已。(或许当年该把
这 个类型叫做&byte&,然后现在就可以根据实际情况,使用byte 或short 来把char 通过typedef 定义出来,这样更合适些)于是,使用&%d&或者&%x&打印一个字符,便能得出它的10 进制或16 进制的ASCII 码;反过来,使用&%c&打印一个整数,便可以看到它所对应的ASCII 字符。以下程序段把所有可见字符的ASCII 码对照表打印到屏幕上(这里采用printf,注意&#&与&%X&合用时自动为16 进制数增加&0X&前缀):
for(int i = 32; i & 127; i++) {
printf(&[ %c ]: %3d 0x%#04X\n&, i, i, i);
连接字符串
sprintf 的格式控制串中既然可以插入各种东西,并最终把它们&连成一串&,自然也就能够连
接字符串,从而在许多场合可以替代strcat,但sprintf 能够一次连接多个字符串(自然也可以同时
在它们中间插入别的内容,总之非常灵活)。比如:
char* who = &I&;
char* whom = &CSDN&;
sprintf(s, &%s love %s.&, who, whom); //产生:&I love CSDN. &
strcat 只能连接字符串(一段以&&结尾的字符数组或叫做字符缓冲,null-terminated-string),但有时我们有两段字符缓冲区,他们并不是以 &&结尾。比如许多从第三方库函数中返回的字符数组,从硬件或者网络传输中读进来的字符流,它们未必每一段字符序列后面都有个相应的&&来结尾。如果直接 连接,不管是sprintf 还是strcat 肯定会导致非法内存操作,而strncat 也至少要求第一个参数是个null-terminated-string,那该怎么办呢?我们自然会想起前面介绍打印整数和浮点数时可以指定宽度,字符串 也一样的。比如:
char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', 'N'};
sprintf(s, &%s%s&, a1, a2); //Don't do that!
十有八九要出问题了。是否可以改成:
sprintf(s, &%7s%7s&, a1, a2);
也没好到哪儿去,正确的应该是:
sprintf(s, &%.7s%.7s&, a1, a2);//产生:&ABCDEFGHIJKLMN&
这 可以类比打印浮点数的&%m.nf&,在&%m.ns&中,m 表示占用宽度(字符串长度不足时补空格,超出了则按照实际宽度打印),n 才表示从相应的字符串中最多取用的字符数。通常在打印字符串时m 没什么大用,还是点号后面的n 用的多。自然,也可以前后都只取部分字符:
sprintf(s, &%.6s%.5s&, a1, a2);//产生:&ABCDEFHIJKL&
在 许多时候,我们或许还希望这些格式控制符中用以指定长度信息的数字是动态的,而不是静态指定的,因为许多时候,程序要到运行时才会清楚到底需要取字符数组 中的几个字符,这种动态的宽度/精度设置功能在sprintf 的实现中也被考虑到了,sprintf 采用&*&来占用一个本来需要一个指定宽度或精度的常数数字的位置,同样,而实际的宽度或精度就可以和其它被打印的变量一样被提供出来,于是,上面的例子 可以变成:
sprintf(s, &%.*s%.*s&, 7, a1, 7, a2);
sprintf(s, &%.*s%.*s&, sizeof(a1), a1, sizeof(a2), a2);
实际上,前面介绍的打印字符、整数、浮点数等都可以动态指定那些常量值,比如:
sprintf(s, &%-*d&, 4, 'A'); //产生&65 &
sprintf(s, &%#0*X&, 8, 128); //产生&0X000080&,&#&产生0X
sprintf(s, &%*.*f&, 10, 2, 3.1415926); //产生& 3.14&
打印地址信息
有时调试程序时,我们可能想查看某些变量或者成员的地址,由于地址或者指针也不过是个32 位的数,你完全可以使用打印无符号整数的&%u&把他们打印出来:
sprintf(s, &%u&, &i);
不过通常人们还是喜欢使用16 进制而不是10 进制来显示一个地址:
sprintf(s, &%08X&, &i);
然而,这些都是间接的方法,对于地址打印,sprintf 提供了专门的&%p&:
sprintf(s, &%p&, &i);
我觉得它实际上就相当于:
sprintf(s, &%0*x&, 2 * sizeof(void *), &i);
利用sprintf 的返回值
较少有人注意printf/sprintf 函数的返回值,但有时它却是有用的,spritnf 返回了本次函数调用
最终打印到字符缓冲区中的字符数目。也就是说每当一次sprinf 调用结束以后,你无须再调用一次
strlen 便已经知道了结果字符串的长度。如:
int len = sprintf(s, &%d&, i);
对于正整数来说,len 便等于整数i 的10 进制位数。
下面的是个完整的例子,产生10 个[0, 100)之间的随机数,并将他们打印到一个字符数组s 中,
以逗号分隔开。
int main() {
srand(time(0));
char s[64];
int offset = 0;
for(int i = 0; i & 10; i++) {
offset += sprintf(s + offset, &%d,&, rand() % 100);
s[offset - 1] = '\n';//将最后一个逗号换成换行符。
printf(s);
设想当你从数据库中取出一条记录,然后希望把他们的各个字段按照某种规则连接成一个字
符串时,就可以使用这种方法,从理论上讲,他应该比不断的strcat 效率高,因为strcat 每次调用
都需要先找到最后的那个&&的位置,而在上面给出的例子中,我们每次都利用sprintf 返回值把这
个位置直接记下来了。
使用sprintf 的常见问题
sprintf 是个变参函数,使用时经常出问题,而且只要出问题通常就是能导致程序崩溃的内存访
问错误,但好在由sprintf 误用导致的问题虽然严重,却很容易找出,无非就是那么几种情况,通
常用眼睛再把出错的代码多看几眼就看出来了。
?? 缓冲区溢出
第一个参数的长度太短了,没的说,给个大点的地方吧。当然也可能是后面的参数的问
题,建议变参对应一定要细心,而打印字符串时,尽量使用&%.ns&的形式指定最大字符数。
?? 忘记了第一个参数
低级得不能再低级问题,用printf 用得太惯了。//偶就常犯。:。(
?? 变参对应出问题
通常是忘记了提供对应某个格式符的变参,导致以后的参数统统错位,检查检查吧。尤
其是对应&*&的那些参数,都提供了吗?不要把一个整数对应一个&%s&,编译器会觉得你
欺她太甚了(编译器是obj 和exe 的妈妈,应该是个女的,:P)。
sprnitf 还有个不错的表妹:strftime,专门用于格式化时间字符串的,用法跟她表哥很像,也
是一大堆格式控制符,只是毕竟小姑娘家心细,她还要调用者指定缓冲区的最大长度,可能是为
了在出现问题时可以推卸责任吧。这里举个例子:
time_t t = time(0);
//产生&YYYY-MM-DD hh:mm:ss&格式的字符串。
char s[32];
strftime(s, sizeof(s), &%Y-%m-%d %H:%M:%S&, localtime(&t));
sprintf 在MFC 中也能找到他的知音:CString::Format,strftime 在MFC 中自然也有她的同道:
CTime::Format,这一对由于从面向对象哪里得到了赞助,用以写出的代码更觉优雅。
旗下网站:
与非门科技(北京)有限公司 All Rights Reserved.
京ICP证:070212号
北京市公安局备案编号: 京ICP备:号共有 1927 人关注过本帖
标题:接收字符串问题
等 级:青峰侠
帖 子:358
专家分:1852
结帖率:100%
&&已结贴√
&&问题点数:20&&回复次数:6&&&
接收字符串问题
假设定义一个字符串str,以下两个字符串接收语句有什么区别啊?
scanf(&%s&,str);
gets(str);
貌似scanf不能接收空格,一遇到空格则判定字符串输入完毕,而gets可以接收空格,遇到回车时才判定字符串输入完毕,是这样吗?
搜索更多相关主题的帖子:
等 级:论坛游侠
帖 子:60
专家分:123
个人理解是这样……以前好像也验证过……
等 级:千里冰封
帖 子:1554
专家分: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是怎么样的?欢迎来群一起交流进步
来 自:广东潮州
等 级:小飞侠
帖 子:1181
专家分: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.022056 second(s), 8 queries.
Copyright&, BCCN.NET, All Rights Reserved怎么用C语言输出字符串?
怎么用C语言输出字符串?
09-02-27 &
#include &stdio.h&main(){char *printf(&%d %s %d&,number,name,score); }这样也是可以的,另外C还提供了函数输入输出字符串上面用gets(name);输入puts(name) 输出也是可以的
请登录后再发表评论!
#include &stdio.h&main(){char *printf(&%d %s %d&,number,name,score); }这样也是可以的,另外C还提供了函数输入输出字符串上面用gets(name);输入puts(name) 输出也是可以的
请登录后再发表评论!
#include &stdio.h&main(){char *printf(&%d %s %d&,number,name,score); }这样也是可以的,另外C还提供了函数输入输出字符串上面用gets(name);输入puts(name) 输出也是可以的
请登录后再发表评论!
#include &stdio.h&main(){char *printf(&%d %s %d&,number,name,score); }这样也是可以的,另外C还提供了函数输入输出字符串上面用gets(name);输入puts(name) 输出也是可以的
请登录后再发表评论!
呵呵,不太懂,不好意思帮不到你
请登录后再发表评论!
#include &stdio.h&#include &stdlib.h&main(){printf(&输入&);while((i=getchar())!='\n') { putchar(i); }system(&pause&);}
请登录后再发表评论!

我要回帖

更多关于 c语言 数字转字符串 的文章

 

随机推荐