У меня есть два массива символов, и когда их размеры отличаются, программа не читает их правильно - PullRequest
0 голосов
/ 26 декабря 2018

У меня есть программа для выполнения основных задач с двумя массивами символов.Все работает нормально, когда ограничение размера первого равно пределу размера второго, но когда размер первого массива char отличается от размера другого, программа начинает странным образом читать / записывать строки.

Например, если предел первого равен 31, а предел другого равен 5, если набранные символы в первом больше 8 или что-то в этом роде, программа не позволит пользователюнабрал что-нибудь во втором массиве, как будто он уже заполнен.

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

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

#define LIMIT1 31
#define LIMIT2 5

/*Function: void copy_string(char *pointer_destination, char *pointer_source)
Precondition: it needs a pointer to the direction of memory of the first element of two char vectors and the size limit of the 'destination' vector
Postcondition: it puts all the elements of the 'source' vector into the other until the last element that */

void copy_string(char *pointer_destination, char *pointer_source, int LIMd){

    //Variable declaration
    int i = 0;

    /*Cycle for replacing the element of the 'destination' vector by the element of the 'source' vector.
    When the element of the 'destination' OR of the 'source' is the null character, this cycle ends*/
    for(; i < LIMd && *(pointer_source + i) != '\0'; i++){
        *(pointer_destination + i) = *(pointer_source + i);
    }
    *(pointer_destination + i) = '\0';
}

int main(){

    //Variable declaration
    int restart;
    char username[LIMIT1], string2[LIMIT2];//Here we define the limit for obvious reasons

    //Restart cycle starts here
    do{

        //Data input
        printf("Type your username (maximum 30 characters)\n");
        fgets(username, LIMIT1 - 1, stdin);
        fflush(stdin);

        printf("Type a string of maximum 30 characters\n");
        fgets(string2, LIMIT2 - 1, stdin);
        fflush(stdin);

        printf("Your typed username and your typed second string are, respectively:\n");
        fputs(username, stdout);
        fputs(string2, stdout);

        printf("Concatenating, the username is now\n");
        strcat(username, string2);
        fputs(username, stdout);

        printf("Now I'll copy what is in your username and I'll put it in the second string,\n");
        copy_string(string2, username, LIMIT2 - 1);
        fputs(string2, stdout);

    //Restart cycle switch
    printf("Type '0' to close this program, otherwise it'll restart itself\n");
    scanf("%d", &restart);
    fflush(stdin);

    //Restart cycle ends here
    }while(restart);

    return 0;
}

Я ожидал, что если бы размер двух массивов был разным, программа все равно считала бы и записала их правильно (если размер первого равен 3, читайте из пользователя только первыйтри символа и поставьте behing как \ 0, а если размер другого равен 25, сделайте то же самое, но с 25 как ограничение размера)

Ответы [ 3 ]

0 голосов
/ 26 декабря 2018

Предупреждение fgets сохранит \ n, если для его сохранения достаточно места, я думаю, что ваша проблема возникает из-за того, что в ваших примерах конец строки сохраняется хотя бы в имени пользователя.Так что вам нужно удалить его, если он есть.

Предупреждение: вы задаете размер минус 1 для fgets, но fgets уже прочитал заданную длину минус 1, чтобы иметь место для установки нулевого символа в конце.

Обратите внимание на сообщение для чтения второгострока неверна, потому что она указывает длину 30, а не 4.

0 голосов
/ 26 декабря 2018

Вы, кажется, полагаетесь на fflush(stdin) для очистки любого непрочитанного ввода.Это неопределенное поведение в стандартном C, и оно работает только на некоторых платформах как нестандартное расширение.Я подозреваю, что он не работает на вашем, и либо полностью ломает ввод, либо ничего не делает, и заставляет следующий fgets прочитать остаток ввода, предназначенный для предыдущего.

Вместо fflush,Вы можете проверить, заканчивается ли строка, прочитанная fgets, новой строкой ('\n', которую вы, вероятно, хотите удалить, если она там есть).Если нет, продолжайте читать (и отбрасывать) ввод до тех пор, пока не встретится новая строка '\n' или EOF.

(В общем, я бы также рекомендовал не использовать scanf для ввода пользователя - намного легче читатьво временный буфер с fgets и синтаксический анализ с sscanf по мере необходимости.)

Другая очевидная, но не связанная с этим проблема - strcat(username, string2); - она ​​может превышать длину username.Вам нужно оставить как минимум LIMIT2 - 1 дополнительного пространства (которое вы не разрешаете использовать fgets) или просто выделить новый массив правильного размера после того, как вы знаете длину каждого из них.

0 голосов
/ 26 декабря 2018

Вы не очень точны в отношении своего фактического и ожидаемого результата, но я думаю, что это так:

Шаги для воспроизведения:

  1. Запустите программу как опубликовано
  2. Получить подсказку Type your username (maximum 30 characters)
  3. Введите this is an especially long string

Ожидаемый результат:

  • Подсказка, которая говорит Type a string of maximum 30 characters и позволяет вам ввестиновая строка

Фактический результат:

  • Type a string of maximum 30 characters записывается на экран, но программа сразу же продолжается, не давая вам ввести другую строку.

Это происходит потому, что первый fgets настроен на чтение не более 30 символов от пользователя.Если вы введете больше, он будет использовать только первые 30.

Следующее fgets будет затем использовать остаток этой строки вместо новой строки, создавая видимость пропуска приглашения.

Вы должны использовать достаточно большой буфер для размещения строки, чтобы это не было проблемой.Кроме того, вы можете вручную читать и сбрасывать по одному символу за раз, пока не найдете \n, эффективно опустошая stdin остальной части строки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...