此代码应该用作vigenere密码。但是,在运行时,无论您输入什么输入,它都会出现分段错误。我正在为edx的在线CS50课程写这篇文章。如果我告诉它复制适当数量的字符,Isn&#t; t strncpy
是否应该停止发生分段错误?
#include <stdio.h>
#include <stdlib.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[]) {
int result;
if (argc != 2) {
printf("Shame on you!\n");
return 1;
}
string key = argv[1];
string text = GetString();
string cpy_key = NULL;
//strncpy(cpy_key, key, strlen(key));
for (int i = 0, n = strlen(text); i < n; i++) {
strcat(cpy_key, key);
}
cpy_key[strlen(text)] = '\0';
// Main loop starts here
for (int i = 0, n = strlen(text); i < n; i++) {
result = text[i] + cpy_key[i];
if (isupper(text[i]) && (result > 'Z')) {
result = result - 26;
}
if (islower(text[i]) && (result > 'z')) {
result = result - 26;
}
if (isalpha(text[i])) {
printf("%c", result);
} else {
printf("%c", text[i]);
}
}
printf("\n");
return 0;
}
答案 0 :(得分:3)
cs50.h
标头定义typedef char *string;
。
发生核心转储是因为您要复制到空指针:
string cpy_key = NULL;
//strncpy(cpy_key, key, strlen(key));
for (int i = 0, n = strlen(text); i < n; i++) {
strcat(cpy_key, key);
无论是strcat()
还是strncpy()
,您都需要为cpy_key
分配存储空间。如果显示循环,如果输入的字符串是50个字符,则将字符串复制50次,因此您需要分配超过2500个字符才能安全。使用strncpy()
可以正确完成工作 - 只要您分配足够的空间。
请注意,strncpy()
不是一个好用的功能。如果你有一个20 KiB缓冲区并将10字节字符串复制到其中,它会在字符串后写入20470个空字节。如果你有一个50字节的缓冲区并且你复制了75个字节,它会复制50个字节并且不会使缓冲区空终止。两者都不明显;缺乏保证的空终止使其变得危险。有更糟糕的接口(strncat()
是主要候选者 - 长度参数代表什么?)但不是很多。
您需要对加密算法进行一些工作。
您可以查看Vigenere cipher only works up to until dealing with a space in C — why?,看看它是如何完成的。
答案 1 :(得分:1)
一个问题是记忆,即
string cpy_key = NULL;
不分配内存,即它只是一个没有大小的名称。知道这一点然后就必须失败
strcat(cpy_key, key);
在那个调用中,你试图将一个有大小的东西连接到一个没有大小的东西。
答案 2 :(得分:0)
您无需制作key
的副本,只需将key
索引为其模数。
顺便说一下,你应该永远不会使用 strncpy
,它不会做你认为它做的事情,它的语义容易出错,它永远不是适合这项工作的工具。最后一个参数应该是目标数组的大小,但是如果源太大,目标将不会以空终止,如果大小很小而目标很大,这个函数将浪费时间填充整个目标数组将'\0
'字节。不使用strncpy
可以避免许多错误。
同样令人遗憾的是,cs50.h使用string
定义typedef char *string;
。使用这种类型会产生误导和容易出错,特别是对于了解C ++的人。只需使用char *
,它就可以让您的代码更容易被C程序员阅读。我希望你不需要使用这种类型,隐藏在typedef后面的指针通常不是一个好主意。
这是一个更简单的版本:
#include <stdio.h>
#include <stdlib.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char *argv[]) {
int result;
if (argc != 2) {
printf("Shame on you!\n"); // you might want to be more explicit ;-)
return 1;
}
char *key = argv[1];
int klen = strlen(key);
char *text = GetString();
if (!text) {
/* end of file or read error */
return 1;
}
// Main loop starts here
for (int i = 0, n = strlen(text); i < n; i++) {
result = text[i] + key[i % len];
if (isupper((unsigned char)text[i]) && result > 'Z') {
result = result - 26;
}
if (islower((unsigned char)text[i]) && result > 'z') {
result = result - 26;
}
if (isalpha((unsigned char)text[i])) {
printf("%c", result);
} else {
printf("%c", text[i]);
}
}
printf("\n");
return 0;
}
提示:您的 vigenere 不正确,如果result = text[i] + key[i % len] - 'A';
全部为大写,则应使用key
。
答案 3 :(得分:-1)
这是C还是C ++?在C中,您需要为char数组(字符串)自己分配空间:
char *cpy_key = 0 ;
...
size_t key_len = strlen (key) + 1 ; // adding space for terminating NULL
...
cpy_key = malloc ( key_len ) ; // add error management here
...
strncpy ( cpy_key , key , key_len ) ; // add error management here
...
free ( cpy_key ) ; // when you don't need it anymore