- 本文主要通过一道题目来讲解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()等都是不错的方法。相信通过本篇文章的学习,你对这方面的题目将不再存有疑问。



















