算法提高 9-3摩尔斯电码
#include<stdio.h>
#include<string.h>
char str[1005]={'\0'},tmp[1005]={'\0'},c;
int i,j,k;
char alpha[27][5]=
{"*-","-***","-*-*","-**","*","**-*","--*","****","**",
"*---","-*-","*-**","--","-*","---","*--*","--*-","*-*",
"***","-","**-","***-","*--","-**-","-*--","--**"
};//字母表
void compare(char *s)
{
for(k=0;;k++)
{
if(!strcmp(s,alpha[k]))
{
c='a'+k;//遇到对的‘人’就给它加上‘a’
printf(" %c ",c);
break;
}
}
}
int main()
{
while(~scanf("%s",str))//这个循环针对整行
{
i=0;
while(1)//这个循环针对摩斯密码的独立单位(字符)
{
j=0;
while(str[i]!='|'&&str[i]!='\0')
{
tmp[j]=str[i];
j++;
i++;
}
i++;//因为停止的地方是间隔符或者结束符,要想继续就要给i +1,后来发现这个与scanf("%s")混合产生了意外的bug,因为如果之前输入长字符串,再输入短字符串,本意是到了结尾在结束,为了方便与'|'一起处理,就采用了i++(一开始是想,反正结尾后面也是'\0',i++
什么的不影响吧)(惨痛的教训:答:实际上第二次s的情况是*'\0'**'\0' puts没有把它显现出来是因为s[1]='\0' 于是就产生了两个字符,真是废物利用哈。。。)
compare(tmp);
for(k=0;k<j;k++) tmp[k]='\0';
/*memset(tmp,0,1005*sizeof(char));*/
if(str[i]=='\0') break;
}
printf("\n");
//for(k=0;k<i;k++) str[k]='\0';
memset(str,'\0',sizeof(str));
}
return 0;
}
然后学到了两个知识点:
menset和scanf("%s",str)\
memset
为重置函数,第一个参数是需要重置的数组名,第二个是指定的元素要重置的新值,第三个是要修改的元素范围——从头开始算的n个内存单位,用n*sizeof(char)来表示(也可以是int)(暂时不对(不知为何))——
memset函数按字节对内存块进行初始化,所以不能用它将int数组初始化为0和-1之外的其他值(除非该值高字节和低字节相同)。详细解释:
因为第一个程序的数组a是字符型的,字符型占据内存大小是1Byte,而memset函数也是以字节为单位进行赋值的,所以你输出没有问题。而第二个程序数组a是整型的,使用 memset还是按字节赋值,这样赋值完以后,每个数组元素的值实际上是0x01010101即十进制的16843009。
如果用memset(a,1,20),就是对a指向的内存的20个字节进行赋值,每个都用数1去填充,转为二进制后,1就是00000001,占一个字节。一个int元素是4字节,合一起是0000 0001,0000 0001,0000 0001,0000 0001,转化成十六进制就是0x01010101,就等于16843009,就完成了对一个int元素的赋值。
说明:如果我们想要将某个数组清零,我们通常会使用memset(a,0,sizeof(a))这样的代码来实现(方便而高效),但是当我们想将某个数组全部赋值为无穷大时(例如解决图论问题时邻接矩阵的初始化),就不能使用memset函数而得自己写循环了(写这些不重要的代码真的很痛苦),我们知道这是因为memset是按字节操作的,它能够对数组清零是因为0的每个字节都是0,现在好了,如果我们将无穷大设为0x3f3f3f3f(即#define INF 0x3f3f3f3f),那么奇迹就发生了,0x3f3f3f3f的每个字节都是0x3f!所以要把一段内存全部置为无穷大,我们只需要memset(a,0x3f,sizeof(a))。
说明:如果我们想要将某个数组清零,我们通常会使用memset(a,0,sizeof(a))这样的代码来实现(方便而高效),但是当我们想将某个数组全部赋值为无穷大时(例如解决图论问题时邻接矩阵的初始化),就不能使用memset函数而得自己写循环了(写这些不重要的代码真的很痛苦),我们知道这是因为memset是按字节操作的,它能够对数组清零是因为0的每个字节都是0,现在好了,如果我们将无穷大设为0x3f3f3f3f(即#define INF 0x3f3f3f3f),那么奇迹就发生了,0x3f3f3f3f的每个字节都是0x3f!所以要把一段内存全部置为无穷大,我们只需要memset(a,0x3f,sizeof(a))。
如:
1
2
3
4
5
6
|
struct
sample_struct
{
char
csName[16];
int
iSeq;
int
iType;
};
|
对于变量
1
|
struct
sample_struct stTest;
|
一般情况下,清空stTest的方法:
1
2
3
|
stTest.csName[0]={
'\0'
};
stTest.iSeq=0;
stTest.iType=0;
|
用memset就非常方便:
1
|
memset
(&stTest,0,
sizeof
(sample_struct));//是
|
如果是数组:
1
|
structsample_struct TEST[10];
|
则
1
|
memset
(TEST,0,
sizeof
(struct sample_struct)*10);
|
另外:
理的。
@百度百科
例如:
#include<stdio.h>
#include<string.h>
void rece(char *s)//在函数的接口中可以用 char*s 但当在主函数里*s代表指针指向的内容是只读的,就不能进行修改
{
memset(s,'b',2*sizeof(char));
}
int main()
{
char a[777]="nihaoma";
memset(a,'r',3*sizeof(char));
puts(a);
rece(a);
puts(a);
return 0;
}
拓展:
memset(void *s, int ch,
size_t
n);中key实际范围应该在0~~255,因为该函数只能取ch的后八位赋值给你所输入的范围的每个字节,比如int a[5]赋值memset(a,-1,sizeof(int )*5)与memset(a,511,sizeof(int )*5) 所赋值的结果是一样的都为-1;因为-1的二进制码为(11111111 11111111 11111111 11111111)而511的二进制码为(00000000 00000000 00000001 11111111)后八位都为(11111111),所以数组中每个字节,如a[0]含四个字节都被赋值为(11111111),其结果为a[0](11111111 11111111 11111111 11111111),及a[0]=-1,因此无论ch多大只有后八位二进制有效,而八位
二进制
[2]
的范围(0~255)YKQ改。而对字符数组操作时则取后八位赋值给字符数组,其八位值作为
ASCII
[3]
码。
scanf这个坑
scanf这个坑
#include<stdio.h>
int main()
{
char s[1005]={'\0'};
while(~scanf("%s",s))
{
puts(s);
/*为什么明明只输出一个“* ”号,
但是却显示s[4]的值存在(显然是第一次遗留下来的)? */
if(s[4]=='\0')
printf("yes\n");
else
printf("no\n");
printf("%c\n",s[4]);
}
return 0;
}
答:实际上第二次s的情况是*'\0'**'\0' puts没有把它显现出来是因为s[1]='\0'
对了,在查找scanf的时候,看到了别人写的有意思的坑和知识点
#include<stdio.h>
int main()
{
char ch1,ch2;
printf("Input for ch1:n");
scanf("%c",&ch1);
printf("ch1=%cn",ch1);
printf("Input for ch2:n");
scanf("%c",&ch2);
printf("ch2=%cn",ch2);
}
表面上看这段程序是没有错的,也可以运行,但运行过程中到 第二个scanf输入值给ch2时,程序并不会停止下来等待你输入,而是直接运行到最后一个printf !
为什么?当时百思不得其解。。。
今天上网查了下才知道,原来scanf是从标准输入缓冲区中读取输入的数据,而%c的字符输入格式会接收回车字符,在输入第一个scanf时输入字符后按回车结束,输入缓冲中保存了这个回车符,遇到第二个scanf时,它自动把这个回车符赋给了ch2 。而如果第二个scanf的输入格式不是%c时,由于格式不匹配,这个回车符会被自动忽略,所以只有在连续输入两个%c的格式时才会出现这样的问题!
问题四 如何处理scanf()函数误输入造成程序死锁或出错?
#include <stdio.h>
int main()
{
int a,b,c; /*计算a+b*/
int main()
{
int a,b,c; /*计算a+b*/
scanf("%d,%d",&a,&b);
c=a+b;
printf("%d+%d=%d",a,b,c);
}
c=a+b;
printf("%d+%d=%d",a,b,c);
}
如上程序,如果正确输入a,b的值,那么没什么问题,但是,你不能保证使用者每一次都能正确输入,一旦输入了错误的类型,你的程序不是死锁,就是得到一个错误的结果,呵呵,这可能所有人都遇到过的问题吧?
解决方法:scanf()函数执行成功时的返回值是成功读取的变量数,也就是说,你这个scanf()函数有几个变量,如果scanf()函数全部正常读取,它就返回几。但这里还要注意另一个问题,如果输入了非法数据,键盘缓冲区就可能还个有残余信息问题。
正确的例程:
#include <stdio.h>
int main()
{
int a,b,c; /*计算a+b*/
int main()
{
int a,b,c; /*计算a+b*/
while(scanf("%d,%d",&a,&b)!=2)fflush(stdin); /*很有趣的代码*/
c=a+b;
printf("%d+%d=%d",a,b,c);
}
#include <stdio.h>
int main()
{
int i;
char j;
for(i = 0;i < 10;i++)
{
scanf(" %c",&j);/*注意这里%前有个空格*/
printf("%c\n",j);// scanf在工作的时候会省略空格,但是在输入回车后又会被空格控制符(超级重要)吸收
}
}
c=a+b;
printf("%d+%d=%d",a,b,c);
}
#include <stdio.h>
int main()
{
int i;
char j;
for(i = 0;i < 10;i++)
{
scanf(" %c",&j);/*注意这里%前有个空格*/
printf("%c\n",j);// scanf在工作的时候会省略空格,但是在输入回车后又会被空格控制符(超级重要)吸收
}
}
在用"%c"输入时,空格和“转义字符”均作为有效字符。
例:
scanf("%c%c%c",&c1,&c2,&c3);
输入:a□b□c↙
结果:a→c1,□→c2,b→c3 (其余被丢弃)
原来scanf是从标准输入缓冲区中读取输入的数据, 而%c的字符输入格式会接收回车字符,在输入第一个scanf时输入字符后按回车结束,输入缓冲中保存了这个回车符,遇到第二个scanf时,它自动把这个回车符赋给了ch2 。而如果第二个scanf的输入格式不是%c时,由于格式不匹配,这个回车符会被自动忽略,所以只有在连续输入两个%c的格式时才会出现这样的问题!
scanf("%c%c%c",&c1,&c2,&c3);
输入:a□b□c↙
结果:a→c1,□→c2,b→c3 (其余被丢弃)
原来scanf是从标准输入缓冲区中读取输入的数据, 而%c的字符输入格式会接收回车字符,在输入第一个scanf时输入字符后按回车结束,输入缓冲中保存了这个回车符,遇到第二个scanf时,它自动把这个回车符赋给了ch2 。而如果第二个scanf的输入格式不是%c时,由于格式不匹配,这个回车符会被自动忽略,所以只有在连续输入两个%c的格式时才会出现这样的问题!
scanf("%[^/n]",string);scanf用来接收带字符的字符串
@
%* 指定类型的数据但不保存
比如:
百分号(%)与格式符之间的星号(*)表示读指定类型的数据但不保存。因此,
scanf( "%d %*c %d", &x, &y );
对 10/20 的读入操作中,10 放入变量 x,20 放入 y。 --意义好大的,对数据的处理会方便好多
scanf( "%d %*c %d", &x, &y );
对 10/20 的读入操作中,10 放入变量 x,20 放入 y。 --意义好大的,对数据的处理会方便好多
@