Сторнирование строки без использования библиотечной функции - PullRequest
1 голос
/ 19 апреля 2020

Итак, я хочу написать программу, которая будет переворачивать строку, взятую у пользователя.

Вот мой исходный код:

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

int main(int argv, char *argc[]) {
    if (argv != 2) {
        printf("Please enter the number of elements in your string!\n");
        return 1;
    }
    int n = atoi(argc[1]);
    char *c = malloc((sizeof(char) * n) + 1);
    char *o = malloc((sizeof(char) * n) + 1);
    printf("Enter your string - ");
    fgets(c, n, stdin);
    for (int i = 0; i < n + 1; i++) {
        *(o + i) = *(c + (n - 1) - i);
    }
    printf("%s\n", o);
    free(c);
    free(o);
}

Но напечатанный вывод - ничто!

Может кто-нибудь указать, что не так с моим кодом?

Ответы [ 4 ]

2 голосов
/ 19 апреля 2020

Проблема, которая препятствует работе кода, заключается в несоответствии размера контейнеров o и c и размера чтения в fgets, так как fgets завершает нулевую строку, считанную из ввода.

Итак, скажем n = 6, когда вы читаете вашу строку, fgets заменяет 6-й символ нулевым символом-терминатором, при обратном обращении нулевой терминатор теперь будет первым символом в o, по сути, он будет пустой строкой, так как строка представляет собой символьный массив с нулевым символом в конце или байтовый массив.

Чтобы исправить это, задайте fgets размер вашего выделенного пространства.

fgets(c, n + 1, stdin);

И заканчивайте нулем o, когда вы закончите задний ход.

*(o + n) = '\0';

Или

o[n] = '\0'; //you can use this notation which is more readable than dereferencing

Незначительные проблемы:

  • Тот факт, что вы переключаете имена основных аргументов. Обычно это int main(int argc, char * argv[]). Это может сбить с толку тех, кто читает ваш код.
  • char *c = malloc((sizeof(char) * n) + 1); имеет ненужные логи c, это может быть char *c = malloc(n + 1);, char имеет размер в один байт.
  • Существует основная проблема с логикой c программы, когда введенная строка короче, чем то, о чем вы просите пользователя, выходной результат не будет желательным, вы можете приложить дополнительные усилия, чтобы защитить ваш код от ошибочных вводов.

Все Учитывая все это, принимая ваш код за основу, это может быть что-то вроде:

//Only the changed parts are represented, the rest is the same
#include <string.h> //for strlen
    //...
    if (argc != 2 || atoi(argv[1]) < 1) { //n must be positive (I switched argv and argc)
        printf("Please enter the number of elements in your string!\n");
        return 1;
    }

    size_t n = atoi(argv[1]); //size_t type more suited for sizes
    char *c = malloc(n + 1);
    char *o = malloc(n + 1);
    //...
    fgets(c, n + 1, stdin);   //as stated n + 1 size argument 

    if(strlen(c) < n) {    //if the length of inputed string is shorter than intended
        puts("The string size shorter than stated!");
        return 1;
    }
    //...
    for (size_t i = 0; i < n + 1; i++) { //repalced int iterator type whith size_t
    //...
    o[n] = '\0'; //null terminate o
    //...
2 голосов
/ 19 апреля 2020

В вашей программе несколько проблем:

  • почему вам требуется аргумент для количества символов? было бы намного проще принять максимальную длину и определить char массивы в main() с автоматическим c хранилищем.

  • , оператор char *c = malloc((sizeof(char) * n) + 1); вычисляет правильный размер выделения, но случайно, потому что sizeof(char) всегда 1. Вы должны написать char *c = malloc(n + 1); или char *c = malloc(sizeof(*c) * (n + 1));.

  • , так как fgets() будет хранить новую строку, вы должны увеличить размер выделения на 1, чтобы не оставлять новую строку во входном потоке, но вам нужно избегать включения новой строки в символы для обратного. Во всех случаях вы должны передать размер массива в fgets(), а не n, потому что fgets() сохранит только 1010 * байтов в массиве и установит c[n - 1] в нулевой терминатор, что приведет к обращению строка, начинающаяся с нулевого терминатора, что делает ее пустой строкой.

  • вы не проверяете, удалось ли fgets() при чтении стандартного ввода.

  • Вы не вычисляете количество символов для обратного. Если пользователь ввел меньше символов, чем n, вы будете транспонировать байты сверх тех, которые были введены, возможно, нулевые байты, что сделает обратную строку пустой (это хорошее объяснение того, что вы наблюдаете).

  • транспозиция l oop должна повторяться для i = 0, в то время как i < n, а не n + 1.

  • вы не устанавливаете нулевой терминатор в конце целевой массив. Этот массив выделяется с помощью malloc(), поэтому он не инициализирован.

Вот модифицированная версия:

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

int main(int argv, char *argc[]) {
    if (argv != 2) {
        printf("Please enter the maximum number of characters in your string!\n");
        return 1;
    }
    int n = atoi(argc[1]);
    if (n < 1) {
        printf("Invalid number of characters: %d\n", n);
        return 1;
    }
    // allocate 1 extra byte for the newline, one more for the null terminator
    char *buf = malloc(n + 2);
    char *out = malloc(n + 2);
    printf("Enter your string: ");
    if (!fgets(buf, n + 2, stdin)) {
        printf("no input\n");
        return 1;
    }
    // get the number of characters in the input before the newline, if any
    int len;
    for (len = 0; buf[len] && buf[len != '\n'; n++)
        continue;
    // if you can use the library function `strcspn()`, replace the for loop with this:
    //len = strcspn(buf, "\n");

    // copy the string in reverse order
    for (int i = 0; i < len; i++) {
        out[i] = buf[len - 1 - i];
    }
    // set the null terminator
    out[len] = '\0';
    printf("%s\n", out);
    free(buf);
    free(out);
    return 0;
}

Также возможно, что вы запустите свою программу из IDE в системе, которая закрывает окно терминала, как только программа завершается. Это помешает вам увидеть результат. Добавьте getchar(); перед return 0;, чтобы исправить эту проблему, или запустите программу вручную из окна оболочки.

2 голосов
/ 19 апреля 2020

что не так с моим кодом!

Основные функциональные проблемы включают в себя:

Для чтения "12345\n" с fgets() требуется не менее 6 байтов, 7 лучше 1 .

Отсутствует нулевой символ в o[]

С fgets(c, n, stdin), c[n-1] является нулевым символом и с "реверсом", поскольку код принимает n символов, c[n-1] становится o[0], и поэтому код печатает пустую строку.

  // fgets(c, n, stdin);  // too small
  fgets(c, n + 1, stdin);  

  // add before printing.
  o[n] = '\0';

Существуют другие незначительные проблемы.


1 Также увеличить выделение, а затем отключить \ n от ввода.

1 голос
/ 19 апреля 2020

Ваша программа потерпит неудачу, если значение n не соответствует количеству символов во входной строке, главным образом потому, что вы не инициализируете выделенную память.

e.g.

n = 10
c = "hello"  

длина c равна 5 но вы выделили 11 байтов, поэтому байты после hello \ n \ 0 неинициализированы в c, поскольку fgets не заполнит их для вас.

в памяти это выглядит примерно так

    +---+---+---+---+---+---+---+---+---+---+---+
c ->| h | e | l | l | o |\n |\0 |   |   |   |   |
    +---+---+---+---+---+---+---+---+---+---+---+

когда вы переворачиваете строку с помощью

*(o + i) = *(c + n - 1 - i)

, поскольку вы используете n в качестве смещения для начала копирования символов, вы начинаете за пределами позиции копирования "привет \ n \ 0" 9 (10 - 1 - 0) и помещая это как первый символ в o, но, поскольку все c не инициализировано, может быть что угодно, даже даже \0, который может объяснить, почему вы ничего не печатаете.

лучше, чтобы после прочтения строки вычислить длину строки с помощью простого значения для l oop

int len = 0;
for (len = 0; c[len] && c[len] != '\n'; ++len);

, а затем использовать len в качестве смещения вместо n

*(o + i) = *(c + len - 1 + i)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...