- 本文主要通过一道题目来讲解C语言相关的简单加密和解密,以及如何读入带有空格的字符串
小试牛刀
-
题目描述
在情报传递过程中,为了防止情报被截获,往往需要对情报用一定的方式加密。我们给出一种最简单的加密方法,对给定的一个字符串,把其中从 a∼y,A∼Y 的字母用其后继字母替代,把 z 和 Z用 a 和 A 替代,其他非字母字符不变。请根据该加密规则将输入的密码进行解密。
提示:这里需要进行解密操作,而不是加密。
-
输入格式
一行,加密后的字符串,长度不多于 10000 个字符。
-
输出格式
一行,将密码解密后的字符串。
-
输入输出样例
输入
Ifmmp ! Ipx bsf zpv!
输出
Hello ! How are you!
根据题目的描述,我们的任务就是解密,即每个字母都由其前驱代替,a由z代替,A由Z代替,其余字符不变。
下面我们尝试写出代码:
- 方法一: 利用
while()
循环,结合getchar()
逐个读入并解密赋值,当读到'\n'
时自动结束读入,再输出即可。
#include<iostream>
using namespace std;
char s[10001];
char c;
int i;
int main(void)
{
while ((c = getchar()) != -1)//这里可以写!=-1 或者!=EOF ,不能写!='\n';
{
if (c == 'a')s[i] = 'z';
else if (c == 'A')s[i] = 'Z';
else if ((c > 'A' && c <= 'Z') || (c > 'a' && c <= 'z')) s[i] = (char)((int)c - 1);
else s[i] = c;
i++;
}
for (int j = 0; j < i; j++)
{
cout << s[j];
}
return 0;
}
- 这个方法的好处在于可以设置特定的终止字符,甚至终止位置,时间复杂度为O(n)。
- 方法二:利用
fgets()
函数直接读入一连串字符(遇到换行符时才停止)。再利用循环进行解密操作,完了输出即可。
#include<iostream>
#include<cstring>
using namespace std;
char s[10005];
char c;
int i;
int main(void)
{
fgets(s, 10001, stdin);
for (int i = 0; i < strlen(s); i++)
{
c = s[i];
if (c == 'a')s[i] = 'z';
else if (c == 'A')s[i] = 'Z';
else if ((c > 65 && c <= 90) || (c > 97 && c <= 122) )s[i] = (char)((int)c - 1);
else;
}
fputs(s, stdout);
return 0;
}
- 这个方法的好处在于可以一次性读入和输出带有空格的长字符串,省去了利用循环带来的时间消耗,时间复杂度为O(n)。
- 方法三:利用
getline()
函数进行指定位数输入,大多数情况下用于一整行(段)输入;strlen()
函数用于获取字符串长度,然后边判断边输出。
#include<bits/stdc++.h>//万能头文件
using namespace std;
char s[10001]; //定义字符串。
int n; //字符串长度。
int main(void)
{
cin.getline(s,10000);
//输入字符串,因为有空格,所以不能用cin<<s。
//最多10000位,末位自动为'\0',所以输入10000位,输入不够10000位就自动停止。
n=strlen(s); //非空字符串长度。
for(int i=0;i<n;i++) //输入时是从第0位到第n-1位。
{
if((s[i]>'a'&&s[i]<='z')||(s[i]>'A'&&s[i]<='Z'))
s[i]--;
//把b-z和B-Z替换成前一个字母。
else if(s[i]=='a')
s[i]='z';
//把a替换成z。
else if(s[i]=='A')
s[i]='Z';
//把A替换成Z。
else;
//其余字符不变
cout<<s[i]; //边改边输出,减少时间消耗
}
return 0;
}
- 这个方法和方法二有些类似,时间复杂度也为O(n)。
- 方法四:先利用
getline(cin,s)
输入带空格的字符串,(对于字符串来说,普通的cin
只能读取没有空格的字符串;)再循环解密输出即可。
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
string s;//这里用STL的字符串
int main(void) {
getline(cin, s);//输入字符串
for (int i = 0; i < s.length(); i++) {
if ((s[i] > 'a' && s[i] <= 'z') || (s[i] > 'A' && s[i] <= 'Z'))
s[i]--;
//把b-z和B-Z替换成前一个字母。
else if (s[i] == 'a')
s[i] = 'z';
//把a替换成z。
else if (s[i] == 'A')
s[i] = 'Z';
//把A替换成Z。
else;
}
cout << s;//直接输出
return 0;
}
- 此方法和方法二,方法三类似,只是输入字符串方式不一样罢了,时间复杂度也为O(n)。
要点剖析:
- 下面我们来看看怎么读入带有空格的字符串,分别从C语言和C++的角度来讲解。
一、C语言中读入带有空格字符串的方法:
- 使用
scanf
函数:scanf
函数默认以空格作为分隔符,可以使用%s
格式化指示符来读取字符串,但它会在遇到空格时停止读取。为了读取带有空格的字符串,可以使用%[^\n]
格式化指示符,它会读取除换行符外的所有字符。
#include <stdio.h>
int main() {
char str[100];
printf("Enter a string: ");
scanf("%[^\n]", str);
printf("You entered: %s\n", str);
return 0;
}
- 使用
fgets
函数:fgets
函数可以读取一行字符串,包括空格。它接受三个参数:要读取的字符串的地址、最大字符数和文件指针(可以是stdin
)。注意,fgets
函数会将换行符也读入字符串中。
#include <stdio.h>
int main() {
char str[100];
printf("Enter a string: ");
fgets(str, sizeof(str), stdin);
printf("You entered: %s\n", str);
return 0;
}
由于gets()
函数的不安全性,我们这里使用fgets()
;
- 使用
getchar
函数:getchar
函数可以逐个字符读取输入。可以使用一个循环来读取字符,直到遇到换行符或达到最大字符数。
#include <stdio.h>
int main() {
char str[100];
printf("Enter a string: ");
int i = 0;
char c;
while ((c = getchar()) != '\n' && i < sizeof(str) - 1) {
str[i++] = c;
}
str[i] = '\0';
printf("You entered: %s\n", str);
return 0;
}
- 这些方法可以读取带有空格的字符串,但需要注意输入的长度限制和处理换行符的方式。选择合适的方法取决于具体的需求和输入格式。
二、C++中读入带有空格字符串的方法:
- 使用
cin
和getline()
:cin
是C++的输入流对象,可以使用>>
操作符来读取字符串。默认情况下,cin
会以空格作为分隔符,因此会在遇到空格时停止读取。为了读取带有空格的字符串,可以使用getline
函数。getline
函数可以从输入流中读取一行字符串,包括空格。它接受两个参数:要读取的字符串对象和输入流对象(可以是cin
)。注意,getline
函数会将换行符也读入字符串中。
#include <iostream>
#include <string>
int main() {
std::string str;
std::cout << "Enter a string: ";
std::getline(std::cin, str);
std::cout << "You entered: " << str << std::endl;
return 0;
}
- 在C++中,还有一种方法可以读取带有空格的字符串,即使用
stringstream
。stringstream
是C++标准库中的一个类,可以将字符串视为流进行处理。通过将输入的字符串存储在stringstream
对象中,可以使用>>
操作符来读取带有空格的字符串。
以下是使用stringstream
读取带有空格的字符串的示例代码:
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::string input;
std::cout << "Enter a string: ";
std::getline(std::cin, input);
std::stringstream ss(input);
std::string str;
while (ss >> str) {
std::cout << "Word: " << str << std::endl;
}
return 0;
}
-
在上述代码中,首先使用
getline
函数读取一行输入字符串。然后,将该字符串存储在stringstream
对象ss
中。使用>>
操作符从ss
中逐个读取字符串,每次读取一个单词,并将其打印出来。 -
这种方法适用于需要逐个处理输入字符串中的单词的场景。可以根据具体需求对读取到的字符串进行进一步处理。
- 还有一种方法,也是使用
getline()
函数。getline()
函数可以动态分配内存,并一次性读取整行输入,并将其存储在指定的字符数组中。
以下是使用getline()
函数读取带有空格的字符串的示例代码:
#include <stdio.h>
#include <stdlib.h>
int main() {
char *str = NULL;
size_t bufsize = 0;
printf("Enter a string: ");
getline(&str, &bufsize, stdin);
printf("You entered: %s", str);
free(str);
return 0;
}
-
在上述代码中,首先定义一个字符指针
str
,并将其初始化为NULL
。然后,使用getline()
函数来读取整行输入,并将其存储在str
指针指向的内存中。getline()
函数会自动分配足够的内存来存储输入的字符串,并将字符串的长度存储在bufsize
变量中。 -
需要注意的是,使用
getline()
函数需要包含头文件<stdlib.h>
,并且在使用完之后需要调用free()
函数来释放动态分配的内存,以防止内存泄漏。
三、总结与思考:
- 本次我们学习了如何输入带有空格的字符串,且分别从C语言和C++的角度进行了讲解,利用
fgets()
,getline()
,getchar()
等都是不错的方法。相信通过本篇文章的学习,你对这方面的题目将不再存有疑问。