Взятие строкового ввода с использованием указателей в c вызывает ошибку сегментации в одной функции. Тот же блок кода работает нормально для другой функции? - PullRequest
1 голос
/ 28 апреля 2020

Итак, я хочу принять ввод имен в виде строк, используя указатели char *. Я посмотрел в Интернете и нашел решение, предоставив память моего указателя с помощью mallo c, а затем взяв ввод с помощью scanf, как показано ниже:

  char *userInput = (char*)malloc(20 * sizeof(char));
  printf("\nEnter a name: ");
  scanf("%s",userInput);
  char *name = (char*)malloc(getLength(userInput)* sizeof(char));
  name = userInput;
  if(name == NULL){
    printf("Memory not allocated");
    exit(0);
  }
  free(userInput);

Это работает, поэтому я скопировал и вставил его в другая функция, для которой требуется аналогичный ввод, как показано ниже:

  char *userInput = (char*)malloc(20 * sizeof(char));
  printf("\nEnter a name: ");
  scanf("%s",userInput);
  char *searched = (char*)malloc(getLength(searched)* sizeof(char));
  searched = userInput;
  if(searched == NULL){
    printf("Memory not allocated");
    exit(0);
  }
  free(userInput);

Но когда я запускаю код для этой функции, она дает мне «выход, ошибка сегментации».

Любые идеи о том, почему не работает во второй функции?

EDIT: getLength () - это функция, которая возвращает длину заданной строки.

Ответы [ 2 ]

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

Здесь два кодовых блока отличаются:

char *name = (char*)malloc(getLength(userInput)* sizeof(char));
      ^^^^                           ^^^^^^^^^

char *searched = (char*)malloc(getLength(searched)* sizeof(char));
      ^^^^^^^^                           ^^^^^^^^^

Второй использует searched дважды. Поэтому вы по-разному корректно изменяете исходный код.

Однако обратите внимание, что оба кодовых блока неверны.

Есть несколько проблем с кодом (оба примера).

scanf("%s",userInput); очень плохо, так как позволяет пользователю переполнять ваш буфер. Взгляните на fgets вместо этого или, по крайней мере, выполните scanf("%19s",userInput);

Здесь:

char *name = (char*)malloc(getLength(userInput)* sizeof(char));
name = userInput;

строка malloc бесполезна, поскольку вы перезаписываете name с помощью userInput сразу после. Таким образом, все, что дает malloc, - это утечка памяти.

И здесь

free(userInput);

вы освобождаете память, на которую указывает userInput. Однако, поскольку вы сделали name = userInput;, - это также память, на которую указывает name. Таким образом, после освобождения ни один из указателей не действителен.

Я предполагаю, что вместо:

name = userInput;

вы хотели бы

strcpy(name, userInput);

Это сказало - я Я не знаю, что такое getLength, но, возможно, malloc должно быть:

char *name = (char*)malloc(1 + getLength(userInput)* sizeof(char));
                           ^^^

, чтобы получить память для завершения строки. По крайней мере, это то, что вы делаете при использовании strlen

Итак:

  char *userInput = malloc(20);
  if(userInput == NULL){
    printf("Memory not allocated");
    exit(0);
  }

  printf("\nEnter a name: \n");
  scanf("%19s",userInput);

  char *searched = malloc(1 + strlen(userInput ));
  if(searched == NULL){
    printf("Memory not allocated");
    exit(0);
  }

  strcpy(searched, userInput);
  free(userInput);

Но ... какова реальная цель кода?

Кажется, что searched будет содержать (в динамической c выделенной памяти) строку, введенную пользователем и , что количество динамически c выделенной памяти должно быть точно что требуется для хранения строки.

Это может иметь смысл в некоторых приложениях, но не в вашем случае!

Первый malloc предназначен для 20 символов. Следовательно, второй malloc будет для 20 или менее символов.

Поскольку malloc требует дополнительной памяти и некоторых требований выравнивания, объем реальной памяти, требуемый, например, malloc(20), составляет более 20 байт. Другими словами - разница в реальной памяти , используемой malloc(20) и malloc(10), вероятно, будет небольшой. Таким образом, сама идея кода довольно бесполезна - вы не экономите значительную память, выполняя второе malloc и копирование строки.

Поэтому вы должны просто сделать:

  char *searched = malloc(20);
  if(searched == NULL){
    printf("Memory not allocated");
    exit(0);
  }

  printf("\nEnter a name: \n");
  scanf("%19s",searched);

  // Go on using searched
  ...
  ...


  // Somewhere later in the code, call free
  free(searched);

Исходный код имеет смысл, только если ваша программа иногда получает очень длинные строки в качестве входных данных, а иногда и очень короткие. В этом случае первый malloc будет для гораздо большего числа, например, 1000000 символов, и затем имеет смысл скопировать входные данные в меньший буфер впоследствии.

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

Код, который вы нашли в Интернете, если вы правильно его воспроизвели, неверен. Проблема в том, что вы освобождаете userInput, даже если searched указывает на эту память.

Вы должны скопировать строку из userInput в searched перед ее освобождением.

Но нет необходимости использовать динамическое выделение c для userInput. Вы можете просто использовать локальный массив.

Вы должны использовать длину userInput при выделении searched. И вам нужно добавить 1, чтобы освободить место для нулевого терминатора.

Прежде чем пытаться скопировать userInput в него, проверьте, было ли выделение успешным.

  char userInput[20];
  printf("\nEnter a name: ");
  scanf("%19s",userInput); // limit input length to 19 so it fits in userInput
  char *searched = malloc((strlen(userInput)+1)* sizeof(char));
  if(searched == NULL){
    printf("Memory not allocated");
    exit(0);
  }
  strcpy(searched, userInput);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...