Почему scanf не работает должным образом при записи в строковый литерал?

include<stdio.h>
int main()
{
    //char b[10];
    char *a="goodone";
    //a=b;

    scanf("%s",a);//this scanf fails and thow segmentation fault.
    printf("%s",a);

} 

Почему это не работает? Я много пробовал с этим scanf, но, когда я резервирую память для своей переменной a * (назначая a = b (прокомментированный)), она отлично работает. В противном случае это не так. Я считаю, что char * a выделит некоторую память для своей строки ( "goodone" ) и вернет эту ячейку памяти в ее значение. И printf отлично работает с этой верой, почему scanf нет? пожалуйста, спаси меня от этого....

Ответ 1

Это потому, что вы инструктируете scanf записывать данные, которые он считывает, в память, выделенную для значения const char*, то есть в постоянную память.

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

char *a="goodone";

к

char a[]="goodone";

Обратите внимание, что это также небезопасно: он может упасть, когда пользователь вводит более семи символов. Добавьте ограничение к вашему спецификатору формата, чтобы решить эту проблему:

scanf("%7s",a);

P.S. Закомментированный a=b работает отлично, потому что он не изменяет строчную константу; скорее, он изменяет указатель на константу символа, который разрешен.

Ответ 2

char *a - это просто указатель на char. Когда вы назначаете ему "goodone", он указывает на этот строковый литерал (который доступен только для чтения) и scanf пытается перезаписать эту строку в памяти, которая вызывает сбой.

Если вы назначили ему b, то у вас есть a, указывающий на область записи для записи размером 10 char (т.е. строку с максимальной длиной 9 + завершающий NUL). Поэтому он работает до тех пор, пока scanf не хранит ничего дольше, чем там.

Аналогичным образом вы можете сделать a массив вместо указателя (т.е. char a[] = "goodone";). Снова вам нужно следить за тем, чтобы не хранить там дольше.