Я понятия не имею, почему я получаю ошибки ошибки сегментации

#include <stdio.h>
#include <cs50.h> //stdlib.h is included in cs50.h so I don't need it
#include <string.h>
#include <ctype.h>
#include <math.h>

int main(int argc, string argv[]) // command line input
{
    if(argc != 2) // check if there is only one input
    {
        printf("error\n");
        return 1;
    }

    int commandlength = strlen(argv[1]); // find string length of command string

    string key[commandlength + 1]; // taking the key from the input and putting it in something that will take less typing later

    for(int i = 0; i < commandlength; i++) // check if every char in the string is a letter
    {
        if(isalpha(argv[1][i]))
            continue;

        else
        {
            printf("error\n");
            return 1;
        }
    }

    strcpy(key[commandlength], argv[1]); // copy key from command line into a string called key
    string input = GetString();
    int inputlength = strlen(input); // length of string typed in when prompted
    int k = 0; // this will be used to iterate the key separately from i, since the key only iterates when applied to an alpha

    for(int i = 0; i < inputlength; i++)
    {
        if(ispunct(input[i]))
            printf("%c", input[i]);

        if(isspace(input[i]))
            printf("%c", input[i]);

        if(isupper(input[i]))
        {
            printf("%c", (input[i] + atoi(key[k]) % commandlength - 65) % 26 + 65);
            k++;
        }

        if(islower(input[i]))
        {
            printf("%c", (input[i] + atoi(key[k]) % commandlength - 97) % 26 + 97);
            k++;
        }        
    }

    printf("\n");
    return 0;
}

Перед чтением, пожалуйста, имейте в виду, что я студент. Гораздо выгоднее получить подробное объяснение, чем просто строку кода с надписью "вот, пожалуйста, я исправил это". Я буду ссылаться на этот пост в своем представлении, и у нас есть очень строгие правила относительно академической честности и того, что копирование против помощи, и я был бы очень признателен, если бы об этом помнили.

Целью этого проекта является создание надежного шифра. Ниже приведены инструкции моего учителя:

Ваша последняя задача на этой неделе - написать в vigenere.c программу, которая шифрует сообщения с использованием шифра Vigenère. Эта программа должна принимать один аргумент командной строки: ключевое слово k, состоящее полностью из буквенных символов. Если ваша программа выполняется без каких-либо аргументов командной строки, с более чем одним аргументом командной строки или с одним аргументом командной строки, который содержит любой не алфавитный символ, ваша программа должна немедленно выдать жалобу и завершиться, причем main возвращает 1 (тем самым означает ошибку, которую могут обнаружить наши собственные тесты). В противном случае ваша программа должна продолжить запрашивать у пользователя строку открытого текста p, которую она затем должна зашифровать в соответствии с шифром Вигенера с помощью k, в конечном итоге вывести результат и выйти, а main вернет 0.

Что касается символов в k, вы должны рассматривать A и a как 0, B и b как 1, …, а Z и z как 25. Кроме того, ваша программа должна применять шифр Вигенера только к символу в p, если этот символ письмо. Все остальные символы (цифры, символы, пробелы, знаки пунктуации и т. Д.) Должны выводиться без изменений. Более того, если ваш код собирается применить j-й символ k к i-му символу p, но последний окажется не алфавитным символом, вы должны подождать, чтобы применить этот j-й символ k к следующему алфавитному символу в p; Вы еще не должны перейти к следующему символу в k. Наконец, ваша программа должна сохранять регистр каждой буквы в p.

Я почти уверен, что выполнил требования для итерации кода, удостоверился, что ключ зацикливается, если он короче шифруемой фразы, и убедился, что я не применяю ключ к не-буквенным символам. Тем не менее, я получаю значение по умолчанию для сегментирования, прежде чем мне будет предложено ввести строку для шифрования, поэтому я почти уверен, что проблема заключается в верхней части кода. Я немного просмотрел код и до сих пор не могу понять, почему он продолжает сегрегироваться.

4 ответа

Решение

Изменить это утверждение

strcpy(key[commandlength], argv[1]); 

в

strcpy( key, argv[1] ); 

key[commandlength] является объектом типа char, значение которого используется в качестве адреса строки, если вы используете эту недопустимую конструкцию

strcpy(key[commandlength], argv[1]); 

Также не очень хорошая идея использовать continue в вашей петле. Вместо

for(int i = 0; i < commandlength; i++) // check if every char in the string is a letter
{
    if(isalpha(argv[1][i]))
        continue;

    else
    {
        printf("error\n");
        return 1;
    }
}

Я бы просто написал

for(int i = 0; i < commandlength; i++) // check if every char in the string is a letter
{
    if( !isalpha(argv[1][i] ) )
    {
        printf("error\n");
        return 1;
    }
}

И как отметил BLUEPIXY вместо

string key[commandlength + 1]; 

там должно быть

char key[commandlength + 1]; 

при условии, что у вас нет некоторого typedef, похожего на

typedef char string;

Однако, если у вас действительно есть такой typedef, то следующее утверждение

string input = GetString();

будет недействительным, потому что вы пытаетесь вызвать функцию strlen для ввода:

int inputlength = strlen(input); 

И не используйте магические числа в вашем коде, как, например, в этом утверждении

printf("%c", (input[i] + atoi(key[k]) % commandlength - 65) % 26 + 65);

Я полагаю, что 65 - это "А". Так что было бы лучше использовать явно символьный литерал "А" вместо 65.

Я не уверен, что string тип должен быть (в соответствии с main(int argc string argv[]) линия выглядит как char*, Если это так, то вы получите массив указателей на символы со строкой string key[commandlength + 1];

С линией strcpy(key[commandlength], argv[1]);

Вы копируете строку из argv[i] до последнего указателя в массиве, который вы создали. Но так как этому указателю (пока) не назначена какая-либо память. Кроме того, он имеет случайный контент и указывает на случайную ячейку памяти. Таким образом, вы получаете Segfault.

Вероятно, вы хотите один указатель, который имеет stringlength из argv[1] строка как память связана.

Ответ пользователя johanneshau несколько прав. Чтобы добавить к его / ее ответу, вы должны объявить ключ переменной, как показано ниже

string key;

вместо

string key[commandlength + 1];

Затем вы должны назначить память для указанной выше переменной-указателя, потому что string является typedef для char * и, следовательно, она не может хранить какую-либо строку, пока ей не будет выделено некоторое количество памяти.

key = (string)malloc(sizeof(char) * (commandlength + 1));

Приведенная выше строка выделит память для хранения входной строки.

Затем вы должны скопировать входную строку в нее, используя следующий код

strcpy(key,argv[1]);

Итак, теперь у вас есть фактическая строка, скопированная в переменную key.

Прежде чем вернуться из функции (семантически запрограммированной), вы должны освободить память, используя функцию free, поскольку мы динамически распределяли ее, используя функцию malloc в куче.

free(key);

Если у вас нет идеи, скомпилируйте ваш исходный код следующим образом: "gcc -Wall -g source.c"; запустите вашу программу, после сбоя программы запустите "dgb ./prog core"

в GDB типа "Bt", и вы увидите номер строки, где происходит ошибка сегмента

если дамп ядра не может быть создан в рабочем каталоге, выполните следующее: "ulimit -c unlimited" (в среде bash)

Другие вопросы по тегам