我正在尝试编写一个Caesar对用户提供的字符串进行加密的程序,但每次尝试运行它时都会弹出错误“Segmentation Fault”。我做错了什么?
int main(int argc, string argv[])
{
if (argc != 2)
{
return 1;
}
int key = atoi(argv[1]);
printf("Plaintext: ");
string Ptext = get_string();
string cipher = 0;
if(Ptext != NULL)
{
for(int i = 0, n = strlen(Ptext); i < n; i++)
{
if(isalpha(i))
{
if(isupper(i))
{
cipher += toupper(((i + key) % 26));
}
else
{
cipher += tolower(((i + key) % 26));
}
}
cipher += i;
}
printf("Ciphertext: %s", cipher);
printf("\n");
}
}
答案 0 :(得分:2)
根据我在评论中阅读的内容,我们可以解决您的帖子最初缺失的一些信息。有一个typedef char* string
以及一个提供的get_string()
函数。根据这些假设,您首先要分配足够的空间来存储生成的密码字符串。
C中的字符串只是分配了字符数组,因此您需要以某种方式分配该内存。最好的方法是使用malloc
在堆上分配它。
更改此行:string cipher = 0;
至string cipher = malloc(strlen(Ptext) + 1);
这将分配足够的空间来存储生成的密文。现在,您需要以某种方式跟踪索引。添加int size = 0;
现在,将循环更改为:
for(int i = 0, n = strlen(Ptext); i < n; i++)
{
if(isalpha(i))
{
if(isupper(i))
{
cipher[size++] = toupper(((i + key) % 26));
}
else
{
cipher[size++] = tolower(((i + key) % 26));
}
}
else
{
cipher[size++] = i;
}
}
cipher[size] = 0; // for the null terminator
这样做会与您认为+=
会做的事情相同。它会将字符插入分配的字符数组中的正确位置,然后将大小增加1,以便下一个插入位于下一个位置。打印字符串后最后要做的就是调用free(cipher);
以基于malloc
释放分配的内存
我建议查看malloc
和free
的工作原理,以及字符数组在C中的工作方式。这是typedef char* string
的一个陷阱,即摘要离开C中的string
实际上是什么,它是指向char
数组的指针。
答案 1 :(得分:0)
我写了一个工作的Ceasar-cypher-function,它和我的代码一样接近你的代码。
以下是在线测试功能略有改变的变体。我只测试了第二个变体,并且仅使用在线c ++编译器(链接在下面),尽管它是c代码。
我希望你可以用它来推理程序的几个部分。
我试图解释的一点是计算密码字符。
对于大写字符,计算是
'A'+((26 + c -'A' + (key%26)) % 26);
第二个词是
(26 + c -'A' + (key%26)) % 26
//结果是0到25之间的数字,
如果key
仅在-25到25之间,则(key%26)
这个词可能只是key
。
如果key
总是正数或零,则不需要添加26(即(26 +
)。
因此对于0..25的密钥,该术语将是
(c -'A' + key) % 26
c -'A'
将字符c
转换为0..25的数字,然后添加键(=偏移或移位),然后将所有26或更高的数字向下移动术语% 26
。
所以现在你有一个从0到25的数字,它代表了密码字符。 但你真的想要一个从'A'到'Z'的角色,而不是0..25的数字。
你希望0为'A',1为'B',2 - &gt; 'C'...... 24-> Y和25->'Z'。
因此,您将“A”的ascii值添加到数字中。这就是术语'A' +
(源代码中的第一项)的原因。这产生了所需的Ceasar-cipher-char。
正如您可能已经注意到的那样,类型string
有点令人困惑。
我将string
替换为char*
。如果你提供类型string
和函数get_string
的声明,我们可以将它合并到代码中,但在我看来,string也不是c中类型的好名字
如果您对该代码有任何疑问,请询问。
您仍然可以对代码进行一些改进,因为几乎总能做到,例如
26
放入const变量(key%26)
操作一次而不是多次cipher[..]
表示法而不是*pb
所以这是程序:
int main(int argc, string argv[])
{
if (argc != 2)
{
return 1;
}
int key = atoi(argv[1]);
const char * Ptext = get_string();
if(Ptext != NULL)
{
char * cipher = 0;
size_t n = strlen(Ptext);
printf("Plaintext: %s\n", Ptext);
cipher = (char *) malloc((n+1)*sizeof(char));
if (!cipher)
return 1;
char * pb = cipher;
char c;
for(int i = 0 ; i < n; i++)
{
c = Ptext[i];
if(isalpha(c))
{
if(isupper(c))
{
*pb = 'A'+((26 + c -'A' + (key%26)) % 26);
}
else
{
*pb = 'a'+((26 + c -'a' + (key%26)) % 26);
}
}
else
{
*pb = c;
}
++pb;
}
*pb='\0';
printf("Ciphertext: %s", cipher);
printf("\n");
free(cipher);
}
return 0;
}
使用
进行在线测试时,几乎相同的代码略有改动https://www.onlinegdb.com/online_c++_compiler
#include <iostream>
#include <cstring>
using namespace std;
const char hw[] = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG";
const char * get_string()
{
return hw;
}
int main()
{
int key = atoi("-3");
const char * Ptext = get_string();
if(Ptext != NULL)
{
char * cipher = 0;
size_t n = strlen(Ptext);
printf("Plaintext: %s\n", Ptext);
cipher = (char *) malloc((n+1)*sizeof(char));
if (!cipher)
return 1;
char * pb = cipher;
char c;
for(int i = 0 ; i < n; i++)
{
c = Ptext[i];
if(isalpha(c))
{
if(isupper(c))
{
*pb = 'A'+((26 + c - 'A' + (key%26)) % 26);
}
else
{
*pb = 'a'+((26 + c -'a' + (key%26)) % 26);
}
}
else
{
*pb = c;
}
++pb;
}
*pb='\0';
printf("Ciphertext: %s", cipher);
printf("\n");
free(cipher);
}
return 0;
}
显示的结果相同