在c中使用strncpy时出现分段错误
此代码应该用作vigenere密码。但是,在运行时,无论您输入什么输入,它都会出现分段错误。我正在为edx在线CS50课程写这篇文章。是否strncpy
应该阻止分段错误发生,如果我告诉它复制适当的字符数量?在c中使用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;
}
你并不需要做的key
副本,你可以索引key
模长度。
顺便说一句,你应该永远不要strncpy
,它不会做你认为它,它的语义是容易出错,这是从来没有为工作的工具。最后一个参数应该是目标数组的大小,但是如果源太大,目标将不会以null结尾,如果大小很小,目标大,这个函数将浪费时间填充整个目标数组将'\0
'字节。不使用strncpy
将为您节省许多错误。
另外不幸的是,cs50.h定义为string
与typedef char *string;
。使用这种类型会导致误导和错误,特别是对于了解C++的人。只需使用char *
,它使得您的代码更容易被C程序员阅读。我希望你不需要使用这种类型,隐藏在typedefs后面的指针通常不是一个好主意。
下面是一个简单的版本:
#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;
}
提示:您的V @ genere不正确,你应该使用result = text[i] + key[i % len] - 'A';
如果key
是全部大写。
这是C还是C++?在C语言中,你需要在你自己的字符数组(字符串)分配空间:
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
请注意,您正在使用分配'key_len'而不是'key_len + 1'字节的细节。这样创建的字符串不会以null结尾。添加'+ 1'可以让你终止字符串。随着分配时间的更长,你不再需要使用'strncpy()',因为你确保你有足够的空间('strcpy()'可以)。你也可以使用'memmove()'(或甚至是'memcpy()'),它的长度为'key_len + 1'。 –
@JonathanLeffler你(再次)是正确的。现在更新我的答案。谢谢 – mauro
的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?看看它可以做什么。
的一个问题是内存即
string cpy_key = NULL;
也就是说,它只是一个没有尺寸名称不分配内存。认识到这一点那么这一定会失败
strcat(cpy_key, key);
在调用你试图连接之类的大小与大小没有一件事一件事。
你为什么使用'strncpy()'?使用'strcpy()'或者如果你知道目标缓冲区的长度和源缓冲区的长度,确实也使用'memcpy()',除非字符串在循环内部改变,否则不要在循环中使用'strlen()'。 –
@iharob使用strcpy()仍然会导致分段错误。此外,strlen()仅在循环开始时被调用一次,并且被保存为int n。 – Fluffy
在llp开始的时候这样做,它在我看来就像是'for'的条件。你在Linux上吗?或者mac?如果是这样,我建议[valgrind](http://www.valgrind.org),它应该可以帮助你快速发现问题。 –