分段错误 - 代码最近工作

时间:2016-12-06 22:09:07

标签: c

我一直在为作业编写一段代码,而且它已经准备好了。今天我再一次尝试了,但这次我尝试执行程序后得到了一个分段错误(核心转储)消息。

我似乎无法找到错误。它编译没有问题,但在执行时它停止。我真的很感激任何帮助!代码如下所示:

#include <stdio.h>
#include <string.h>
#include <ctype.h> 
#include <stdlib.h>

#define MAX 256

int find_key(char aString[]);
void decrypt(char cipher[], char plain[], int key);

int main(int argc, char *argv[]) {
    FILE *pointer_in = fopen(argv[1], "r");
    FILE *pointer_out = fopen(argv[2], "w");
    char *input_buffer;
    char output_string[MAX];
    long len;
    int key = 0;

    if (pointer_in == NULL) {
        return 1;
    }

    /* Reading entire file into a buffer.
    Finding byte length */
    fseek(pointer_in, 0L, SEEK_END);
    len = ftell(pointer_in);

    /* load the file index to 
    the start of the pointer_in */
    fseek(pointer_in, 0L, SEEK_SET);    

    /* allocate memory to enable 
    buffer to contain the file */
    input_buffer = (char*)calloc(len, sizeof(char));    

    /* if a memorey failure */
    if (input_buffer == NULL) {
        return 1;
    }
    /* read the file into the buffer */
    fread(input_buffer, sizeof(char), len, pointer_in);
    fclose(pointer_in);

    /* key is calculated and passed */    
    key = find_key(input_buffer);

    /* decrypts the input_buffer, using the key and
    passes decrypted text to output_string */
    decrypt(input_buffer, output_string, key);

    /* free up memory */
    free(input_buffer);

    /* prints the output_string to the pointer_out */
    fprintf(pointer_out, "%s", output_string);
    fclose(pointer_out);
}

/* A function to find find the caesar key used
initially to encrypt a file. Done by frequency
analysis of letters and comparing to a a corpus
of most used english letters */

int find_key(char aString[]) {
    char key_holder;
    char alphaLetter[MAX];
    int alphaFreq[MAX];
    int key;

    for (int i = 0; i <= 25; i++) {
        alphaLetter[i] = 'a' + i;  /* Array elements A-Z */
        alphaFreq[i] = 0;          /* Frequency of occurrence */
    }

    for (int i = 0; i < strlen(aString); i++) {
        if (isupper(aString[i]))    /* If indexed character is upper, */
        {                           /* convert to lower by upping ASCII */
            aString[i] += 32;       /* value by the difference between */
        }                           /* lowercase and equivalent uppercase */
        switch(aString[i])          /* letters (32) */
        {
          case 'a':
            alphaFreq[0] += 1;
            break;
          case 'b':
            alphaFreq[1] += 1;
            break;
          case 'c':
            alphaFreq[2] += 1;
            break;
          case 'd':
            alphaFreq[3] += 1;
            break;
          case 'e':
            alphaFreq[4] += 1;
            break;
          case 'f':
            alphaFreq[5] += 1;
            break;
          case 'g':
            alphaFreq[6] += 1;
            break;
          case 'h':
            alphaFreq[7] += 1;
            break;
          case 'i':
            alphaFreq[8] += 1;
            break;
          case 'j':
            alphaFreq[9] += 1;
            break;
          case 'k':
            alphaFreq[10] += 1;
            break;
          case 'l':
            alphaFreq[11] += 1;
            break;
          case 'm':
            alphaFreq[12] += 1;
            break;
          case 'n':
            alphaFreq[13] += 1;
            break;
          case 'o':
            alphaFreq[14] += 1;
            break;
          case 'p':
            alphaFreq[15] += 1;
            break;
          case 'q':
            alphaFreq[16] += 1;
            break;
          case 'r':
            alphaFreq[17] += 1;
            break;
          case 's':
            alphaFreq[18] += 1;
            break;
          case 't':
            alphaFreq[19] += 1;
            break;
          case 'u':
            alphaFreq[20] += 1;
            break;
          case 'v':
            alphaFreq[21] += 1;
            break;
          case 'w':
            alphaFreq[22] += 1;
            break;
          case 'x':
            alphaFreq[23] += 1;
            break;
          case 'y':
            alphaFreq[24] += 1;
            break;
          case 'z':
            alphaFreq[25] += 1;
            break;
          default: break;
        }
    }

    /* bubble sort, so in the end alphaLetter[0]
    will contain most frequent character */
    for (int i = 1; i < 26; i++) {
        if (alphaFreq[0] < alphaFreq[i]) {
            alphaFreq[0] = alphaFreq[i];
            alphaLetter[0] = alphaLetter[i];
        }
    }
    key_holder = alphaLetter[0];
    key = (key_holder - 97) - 4;
    return key;
}

/* A function to decrypt using the key found by
our find_key() function */
void decrypt(char cipher[], char plain[], int key) {
    int string_length = strlen(cipher);
    int ascii_a = 0;

    for (int i = 0; i < string_length; i++) { 
        if (isalpha(cipher[i])) {
            if (islower(cipher[i])) {
                ascii_a = 122;
            } else {
                ascii_a = 90;
            }

            plain[i] = ((cipher[i] - ascii_a - key) % 26) + ascii_a;
        } else {
            plain[i] = cipher[i];
        }
    }
    plain[string_length] = '\0';
}

1 个答案:

答案 0 :(得分:5)

为读取输入文件而分配的缓冲区是一个字节太短:必须分配一个额外的字节并存储空终止符以使其成为C字符串。

您还假设输出消息适合大小为MAX的缓冲区,如果源文件大于MAX-1字节,则该错误不正确。将输入限制为MAX-1个字节或将输出缓冲区分配到适当的大小。

以下是main功能的更正版本:

#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
    FILE *pointer_in, *pointer_out;
    char *input_buffer, *output_string;
    long len;
    int key;

    if (argc < 3) {
        fprintf(stderr, "usage: %s input_file output_file\n", argv[0]);
        return 1;
    }
    pointer_in = fopen(argv[1], "r");
    if (pointer_in == NULL) {
        fprintf(stderr, "cannot open input file %s: %s\n"
                argv[1], strerror(errno));
        return 1;
    }

    /* Get the file size */
    fseek(pointer_in, 0L, SEEK_END);
    len = ftell(pointer_in);
    fseek(pointer_in, 0L, SEEK_SET);    

    /* allocate memory to read the whole file */
    input_buffer = calloc(len + 1, sizeof(char));
    output_string = calloc(len + 1, sizeof(char));

    if (input_buffer == NULL || output_string == NULL) {
        fprintf(stderr, "cannot allocate memory for %ld bytes\n", len + 1);
        return 1;
    }

    /* read the file into the buffer */
    if (fread(input_buffer, sizeof(char), len, pointer_in) != len) {
        fprintf(stderr, "cannot read input file %s\n", argv[1]);
        return 1;
    }
    input_buffer[len] = '\0';
    fclose(pointer_in);

    /* key is calculated and passed */    
    key = find_key(input_buffer);

    /* decrypts the input_buffer, using the key and
    passes decrypted text to output_string */
    decrypt(input_buffer, output_string, key);

    /* prints the output_string to the pointer_out */
    pointer_out = fopen(argv[2], "w");
    if (pointer_out == NULL) {
        fprintf(stderr, "cannot open output file %s: %s\n"
                argv[2], strerror(errno));
        return 1;
    }
    fputs(output_string, pointer_out);
    fclose(pointer_out);
    free(input_buffer);
    free(output_string);

    return 0;
}

您的find_key()功能非常效率低下:

  • 您重新计算每个字符的字符串长度。
  • 您应该计算数组索引,而不是使用巨大的switch

这是一个简化版本:

int find_key(char aString[]) {
    /* This code assumes ASCII: the letters are assumed to be contiguous */
    int alphaFreq[26] = { 0 };
    int c, key;

    for (int i = 0; (c = (unsigned char)aString[i]) != '\0'; i++) {
        if (c >= 'a' && c <= 'z') {
            alphaFreq[c - 'a']++;
        } else
        if (c >= 'A' && c <= 'Z') {
            alphaFreq[c - 'A']++;
        }
    }

    /* find the most frequent character */
    c = 0;
    for (int i = 1; i < 26; i++) {
        if (alphaFreq[c] < alphaFreq[i]) {
            c = i;
        }
    }
    key = c - 4;
    return key;
}