Ввод с указателем на символ и массивом символов - PullRequest
5 голосов
/ 08 марта 2010

рассмотрим код

#include<stdio.h>
int main(void)
{
   char* a;
   scanf("%s",a);//&a and &a[0] give same results-crashes 
   printf("%s",a);
   return 0;
}

почему этот код приводит к сбою? Тогда как этот код, использующий массив символов, работает нормально?

#include<stdio.h>
int main(void)
{
   char a[100];
   scanf("%s",&a[0]);//works fine
   printf("%s",a);
   return 0;
}

разница в том, что массив символов и указатель? Но я знал, что указатель просто указывает на первый элемент, который & & [0] должен работать нормально, но верхний код падает для всех трех, а именно, & a и & a [0]? главное, что я хотел бы узнать, как я могу получить ввод символьного указателя, если я настаиваю на использовании только scanf? Я прошу прощения, если мне не ясно. заранее спасибо :)

Ответы [ 6 ]

9 голосов
/ 08 марта 2010

Поскольку char* a; выделяет место в стеке для символьного указателя, тогда как char a[100]; выделяет пространство для 100 символов.

В первом случае вам нужно выделить некоторую фактическую память для указателя, на которую нужно указать. Причиной вашего сбоя является то, что a задается какое-то произвольное значение (вы его не инициализируете), а когда вы scanf, это именно то место, где записываются данные. Вот если вы просто используете a, давайте назовем этот тип сбоя номер один.

Если вы используете &a, он запишет ваш ввод поверх самого указателя, который оставит вас с указателем, указывающим кто знает где, что приводит к сбою типа номер два. Предполагается, что вы не ввели больше символов, чем переполняет указатель - это повредит стек вызовов, что приведет к другой аварийной ситуации (тип три).

И в качестве совета, пожалуйста, не используйте функции ввода, у которых нет проверки границ, если вы не полностью контролируете, какие данные им представляются. Даже с char[100] кто-то может вызвать переполнение стека в вашем коде, введя больше символов, чем уместится в вашем буфере.

Я считаю, что лучше всего использовать fgets (который может ограничить число читаемых символов) в сочетании с sscanf (хотя, если все, что вы получаете, это строка, sscanf не очень нужно).

4 голосов
/ 08 марта 2010

a ни на что не указывает. Или, на самом деле, он неинициализирован, поэтому указывает куда-то, но не на что-то действительное.

Вы можете предоставить хранилище в стеке, как вы уже пробовали:

#include <stdio.h>
int main()
{
  char x[100];
  char *a = x; // a points to the storage provided by x on the stack
  scanf("%s",a); // should work fine
  printf("%s",a);
  return 0;
}

Обратите внимание, что printf("%s",x); дает точно такой же результат, a указывает на x, поэтому ваша строка будет "жить".

Или вы можете настроить управление памятью, используя malloc

#include <stdio.h>
#include <stdlib.h>
int main()
{
  char *a = malloc (100*sizeof(char)) // a points to the storage provided by malloc
  if (a != null)
    {
      perror ("malloc"); // unable to allocate memory.
      return 1;
    }
  scanf("%s",a); // should work fine
  printf("%s",a);
  free (a); // just remember to free the memory when you're done with it.
  return 0;
}

НТН.

EDIT
Кроме того, до начала комментариев ... Это очень небезопасный код, но я полагаю, вы просто пытаетесь навести порядок в указателях, поэтому я просто попытался подтолкнуть вас в правильном направлении. (Если вам не нужно смотреть на чтение ограниченного объема данных, убедитесь, что он помещается в ваши буферы, если он из какого-то другого источника, чем файл, вам нужно убедиться, что вы получили все это, и так далее, и так далее ).

2 голосов
/ 08 марта 2010

scanf нужно место, куда помещаются символы, которые он читает. Вы можете передать ему указатель на массив символов (что вы делаете во втором примере) или указатель на некоторую память, полученную другим способом (скажем, malloc ()). В первом примере вы передаете ему неинициализированный указатель, поэтому проблемы, которые вы наблюдаете.

2 голосов
/ 08 марта 2010

Вы должны выделить память для a с помощью malloc() перед ее использованием.

1 голос
/ 08 марта 2010

В вашем первом коде a - неинициализированный указатель на символ.Вы пытаетесь выполнить запись в нераспределенную память или зарезервированную память.

Вам необходимо выделить память для входной строки с помощью malloc().


int main(void) {
  char* s;
  /* ... */
  s = malloc(100 * sizeof(*s));
  if (s == NULL) {
    return 1;
  /* ... */
}
1 голос
/ 08 марта 2010

В первом примере a - это «висячий указатель» - это указатель, который содержит адрес некоторой случайной ячейки памяти. В большинстве случаев доступ к этому адресу приведет к сбою. Итог: вам нужно выделить память для.

...