在c中使用strncpy时出现分段错误

时间:2016-01-24 01:44:58

标签: c cs50

此代码应该用作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;
}

4 个答案:

答案 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