Как сделать строку Dynami c? - PullRequest
1 голос
/ 13 июля 2020

Я пытаюсь создать программу, которая, на мой взгляд, должна быть простой. Я хочу попросить слово и сохранить его в векторе с правильным размером (логически более \n). Для этого программа просит пользователя написать слово, оканчивающееся на .. Затем программа читает букву за буквой и сохраняет буквы в строке, которая создается динамически по мере чтения букв.

int main() {
   int i = 0, tam = 0;
   char *cad = (char *)malloc(sizeof(char));
   char c;

   printf("word: ");

   while (c != '.') {
       scanf("%c", c);
       cad[i] = c;
       i++;
       cad = realloc(cad, (i + 1) * sizeof(char));
   }
   cad[i] = '\0';

   for (i = 0; cad[i] == '\0'; i++) {
       tam++;
   }
   printf("tam: %d\n", tam);

   return 0;
}

Я сделал это, но думаю, что это не дает ничего полезного

Ответы [ 4 ]

1 голос
/ 13 июля 2020

Проще использовать getchar() для чтения отдельных байтов из файла. Также проверьте наличие сбоев выделения и перераспределения:

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

int main() {
    int len = 0;
    char *cad, *new_cad;
    int c;

    printf("word: ");

    cad = malloc(len + 1);
    if (cad == NULL) {
        printf("memory allocation failure\n");
        return 1;
    }
    while ((c = getchar()) != EOF && c != '.') {
        cad[len] = (char)c;
        len++;
        new_cad = realloc(cad, len + 1);
        if (new_cad == NULL) {
            printf("memory allocation failure\n");
            free(cad);
            return 1;
        }
        cad = new_cad;
    }
    cad[len] = '\0';

    printf("tam: %d, string: %s\n", len, cad);
    free(cad);

    return 0;
}

Перераспределение строки Dynami c по одному байту за раз неэффективно, но реализация лучшей стратегии - это оптимизация. В первую очередь сосредоточьтесь на правильности, оптимизируйте только в случае необходимости, что доказано тщательным сравнительным тестированием.

0 голосов
/ 13 июля 2020

Два совета:

  1. realloc - относительно дорогая операция, и вы действительно не хотите делать ее для каждого символа. Распространенным методом является увеличение размера буфера вдвое по мере необходимости - это минимизирует общее количество вызовов realloc. Вы можете столкнуться с некоторой внутренней фрагментацией, но в среднем это не должно быть так уж плохо.

  2. Если realloc не может расширить буфер, он вернет NULL и оставит оригинальный буфер на месте. Таким образом, вы не хотите присвоить результат realloc обратно исходному указателю без его предварительной проверки, иначе вы можете потерять ссылку на ранее выделенную память.

Также было бы лучше использовать getchar или fgetc для чтения ввода, а не scanf.

Итак:

#define START_SIZE 2
...
size_t size = START_SIZE;  // tracks the size of the buffer
size_t length = 0;         // tracks the length of the string in the buffer
char *cad = calloc( size, sizeof *cad ); 

/**
 * **ALWAYS** check the result of a malloc, calloc, or realloc call.
 */
if ( !cad )
{
  fprintf( stderr, "Couldn't allocate initial buffer, bailing out here...\n" );
  return EXIT_FAILURE;
}

for ( int c = getchar(); c != '.' && c != EOF; c = getchar() )
{
  /**
   * First, make sure we still have room in our buffer (accounting for the
   * zero terminator) - if we don't, double it.
   */
  if ( length + 1 == size )
  {
    char *tmp = realloc( cad, sizeof *cad * ( 2 * size ) );
    if ( !tmp )
    {
      fprintf( stderr, "realloc failed, exiting loop with what we've read so far\n" );
      break;
    }      
    cad = tmp;
    size *= 2;
  }
  cad[length++] = c;
  cad[length] = 0;   // terminate the string as we go
}
0 голосов
/ 13 июля 2020

Как сделать динамическую c строку?

Прочтите внимательно такую ​​книгу, как Modern C , затем обратитесь на хороший C справочный сайт . Прочтите документацию вашего C компилятора (возможно, G CC) и отладчика (возможно, GDB ). Конечно, внимательно прочтите документацию по каждой функции (например, scanf), которую вы используете.

 while(c != '.'){
   scanf("%c", c);
   cad[i] = c;
   i++;
   cad = realloc(cad, (i + 1)*sizeof(char));
 }

Ваш код выше и неверен, и неэффективен.

Это неправильно, поскольку вы используете scanf (ошибочно: должно быть scanf("%c", &c), но вы действительно хотите использовать getchar ) и reallo c, но не обрабатывать их случай отказа

Это неэффективно, потому что вы, вероятно, не захотите перераспределять строку через каждые l oop. Если у вас очень мало памяти (на практике маловероятно), вам следует подумать об использовании realloc только время от времени (поскольку realloc, вероятно, является дорогостоящей операцией). Например, вы можете сначала malloc буфер размером 128 байт, а realloc - только при необходимости (когда вы прочитали 127 байт), например, newsize = 3 * oldsize / 2 (так что второй раз до 192 байтов и т. Д.) 1049 * ...)

И если вы скомпилировали все предупреждения и отладочную информацию (например, gcc -Wall -Wextra -g), вы получите полезные предупреждения.

0 голосов
/ 13 июля 2020

Внесены все изменения, это должно дать вам желаемый результат.

#include <stdio.h>
#include <stdlib.h>
int main(){
   int i = 0, tam = 0;
   char *cad = (char*)malloc(sizeof(char));
   char c = 'l';

   printf("word: ");

   while(c != '.'){
       c= getchar();
       cad[i] = c;
       i++;
       cad = realloc(cad, (i + 1)*sizeof(char));
   }
   cad[i] = '\0';

/*
As pointed out by Bruno, this for loop just calculates the length of the char array, so commented this
for(i = 0; cad[i] == '\0'; i++){
    tam++;
}
printf("tam: %d\n", tam);
*/
printf("tam: %d\n", i);

   return 0;
}
...