Различаются длины массивов при использовании strlen и полный массив не печатается? - PullRequest
1 голос
/ 11 апреля 2019

Я пытаюсь скопировать строку plaintext в другую строку ciphertext в C, чтобы они имели одинаковую длину и символы массива. Я не могу получить длину строк или содержание, чтобы соответствовать. Любое руководство будет высоко ценится!

Я попытался использовать strlen при инициализации ciphertext того же размера, что и plaintext, а затем скопировать каждый символ plaintext в ciphertext и распечатать обе строки, а также их длины.

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

bool is_number(int input);

int main(int argc, string argv[])
{
    //checking that user provides only one input argument
    if (argc != 2)
    {
        printf("Usage: ./caesar key\n");
        return 1;
    }
    //check that user key input is an integer
    for (int i = 0, l = strlen(argv[1]); i < l; i++)
    {
        if(is_number(argv[1][i]) == 0)
        {
            printf("Usage: ./caesar key\n");
            return 1;
        }
    }

    //prompts user for message
    string plaintext = get_string("plaintext:  ");
    char ciphertext[strlen(plaintext)];
    printf("length p: %lu\n", strlen(plaintext));
    printf("length c: %lu\n", strlen(ciphertext));   
    for (int i = 0; plaintext[i] != '\0'; i++)
    {
        ciphertext[i] = plaintext[i];
        //printf("p[i] = %c\n", plaintext[i]);
        //printf("c[i] = %c\n", ciphertext[i]);
        //printf("i= %i\n", i);
    }
    printf("ciphertext: %s\n", ciphertext);    
}

//checks if a char is a number
bool is_number(int input)
{
    if(input < '0' || input > '9')
    {
        return 0;
    }
    else
    {
        return 1;
    }
}

Когда я запускаю этот код, моя длина строки не совпадает, и ciphertext не печатает все его символы или печатает случайные дополнительные символы.

Пример командной строки:

$ make caesar
clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow    caesar.c  -lcrypt -lcs50 -lm -o caesar
$ ./caesar 1
plaintext:  hello
length p: 5
length c: 6
ciphertext: hell

1 Ответ

3 голосов
/ 11 апреля 2019

Неопределенное поведение (UB)

printf("ciphertext: %s\n", ciphertext); пытается напечатать ciphertext, предполагая, что это строка (последовательность символов, включающая и заканчивающаяся нулевым символом ), которой она не является.

strlen(ciphertext) требуется строка .

В C вспомните строку , должна содержать нулевой символ , иначе это не строка . Для многих функций str...() требуется строка .


Код может попытаться

printf("ciphertext: %.*s\n", (int) strlen(plaintext), ciphertext); 

для печати массива символов до нулевого символа или до длины или строки plaintext.

strlen(ciphertext) просто неверно, поскольку ciphertext не хватает нулевого символа .


Или рассмотрим

char ciphertext[strlen(plaintext) + 1];  // 1 more 
size_t i;
for (i = 0; plaintext[i] != '\0'; i++) {
    ciphertext[i] = plaintext[i];  // ciphertext is not yet a _string_.
}
ciphertext[i] = '\0'; // Now ciphertext is a _string_.

Также обратите внимание:

printf("length p: %lu\n", strlen(plaintext)); не так, как strlen() возвращает size_t, не обязательно unsigned long.

Используйте соответствующий спецификатор и введите.

// printf("length p: %lu\n", strlen(plaintext));
printf("length p: %zu\n", strlen(plaintext));

Подсказка: приведенные ниже 2 являются функционально эквивалентными, вторая - идиоматической в ​​C.

for (int i = 0, l = strlen(argv[1]); i < l; i++)
for (int i = 0; argv[1][i]; i++)
// of better
for (size_t i = 0; argv[1][i]; i++)

`

...