Ошибка сегментации при использовании strncpy в c
Этот код должен работать как надежный шифр. Однако при запуске, независимо от того, какой ввод вы вводите, происходит сбой сегментации. Я пишу это для онлайн курса CS50 по edx. не 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;
}
4 ответа
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-килобайтный буфер и вы скопируете в него 10-байтовую строку, он записывает 20470 нулевых байтов после строки. Если у вас есть 50-байтовый буфер и вы копируете в него 75 байт, он копирует 50 байт и не оставляет нулевой буфер завершенным. Ни то, ни другое не очевидно; отсутствие гарантированного нулевого завершения делает его опасным. Есть худшие интерфейсы (strncat()
является основным кандидатом - что представляет собой параметр длины?), но не многие.
У вас есть работа над алгоритмом шифрования.
Вы могли бы взглянуть на шифр Vigenere, работающий только до тех пор, пока не имеете дело с пробелом в C - почему? чтобы увидеть, как еще это можно сделать.
Одной из проблем является память, т.е.
string cpy_key = NULL;
не выделяет память, т.е. это просто имя без размера. Зная это, это должно провалиться
strcat(cpy_key, key);
В этом вызове вы пытались соединить вещь, которая имеет размер, с вещью без размера.
Вам не нужно делать копию key
Вы можете просто индексировать в key
по модулю его длина.
Кстати, вы никогда не должны использовать strncpy
, он не делает то, что вы думаете, его семантика подвержена ошибкам, он никогда не подходит для работы. Предполагается, что последним аргументом будет размер целевого массива, но если источник слишком велик, конечный объект не будет завершен нулем, а если маленький размер и большой адресат, эта функция будет тратить время на заполнение целого массива назначения. будут ' \0
'байтов. Не используется strncpy
избавит вас от многих ошибок.
Также прискорбно, что cs50.h определяет string
с typedef char *string;
, Использование такого типа вводит в заблуждение и подвержено ошибкам, особенно для людей, которые знают C++. Просто используйте char *
, это делает ваш код намного проще для чтения программистами Си. Я надеюсь, что вы не обязаны использовать этот тип, скрывать указатели за 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;
}
СОВЕТ: Ваш Vigenere неверен, вы должны использовать 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