Ручное построение строки в C с использованием указателей

#c #string #pointers

#c #строка #указатели

Вопрос:

Следующий код компилируется и хорошо выполняется с mingw32 в Windows.

 int main() {
    char *s;
    *s = 65;
    *(s 1) = 66;
    *(s 2) = 0;
    printf("%s", s);
}
  

Это выводит AB. Однако, когда я запускаю тот же код в онлайн-компиляторе, таком как ideone, я получаю ошибку времени выполнения. Вот ссылка на код в ideone. Что не так с кодом?

Комментарии:

1. Вам необходимо выделить память для хранения символов.

Ответ №1:

 *s = 65;
*(s 1) = 66;
*(s 2) = 0;
  

Все эти три оператора вызывают неопределенное поведение, поскольку s указатель не инициализирован.

Например, используйте это (это только для примера, лучшим способом было бы использовать массив напрямую):

  char bla[3];
 char *s = bla;
  

Ответ №2:

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

 int main() {
    char *s = malloc(sizeof(char) * 3);
    *s = 65;
    *(s 1) = 66;
    *(s 2) = 0;
    printf("%s", s);
    free(s);
}
  

Обратите внимание, что вы должны проверить случай, когда malloc возвращает NULL .

Комментарии:

1. Да, вы хотите malloc

2. Второстепенный: считайте malloc(3 * sizeof *s); , что или malloc(3); как sizeof(char) всегда равно 1.

Ответ №3:

Давайте пройдем шаг за шагом и сначала поймем, почему это происходит:

 char *s;
  

переменные в C не инициализируются некоторым постоянным значением, как в некоторых других языках программирования, в C они получают какое-то случайное мусорное значение — означает, что определение int , например, может привести к int с 0 помощью , -2 или 193821 . То же самое с указателями, они ЯВЛЯЮТСЯ переменными, они получают мусорное значение, что означает, что оно указывает КУДА-ТО, неизвестно куда.

 *s = 65;
  

Вы не назначали ей никакой памяти, вы просто сказали «Куда указывает S? Хорошо, идите туда — назначьте 65 «, компьютер ничего не будет делать, кроме этого, он пойдет и назначит 65 там (никто не сказал, что память там доступна). То же самое происходит в следующих строках tow, память не назначается, но вы все равно назначаете ее. Иногда это будет работать, иногда нет.
Если вы хотите назначить память, которую вы будете использовать, malloc но причина, по которой код не будет работать в Сети, заключается в том, что сайт — в отличие от большинства компиляторов — не разрешает этого, код, вероятно, выполняется на его серверах, и сайт не захочет каких-либо неопределенных поведений или проблем в его памяти — тогда сайт не включитвы можете присваивать значения памяти, которые вы не получали или даже не запрашивали. Сайт защищает себя, когда они создавали сайт, они разработали его, чтобы никто не мог привести к его сбою, вы, вероятно, не сможете вызвать у них переполнение буфера, просто используя gets — у него, вероятно, есть предопределенные входные данные — и они, вероятно, не позволят вам определить целочисленный массив с триллионом элементов: P

Комментарии:

1. Спасибо, что явно указали, что я объявлял указатель, который указывал на какое-то случайное место. Теперь это понятнее.

2. @user1720897 нет проблем 🙂

3. static и глобальные переменные в C инициализируются некоторым значением. static Нелокальные, такие как char *s inside main() , не являются.

4. @chux — это не какое-то значение, а 0, как предписано стандартом.

5. @chux Я не знаю, я говорил из знаний, но в основном из опыта, я только что запустил программу (после вашего комментария), скомпилированную с помощью GCC, которая печатает указатель и печатает целое число, оба не инициализированы, и ОБА имеют какое-то случайное мусорное значение: P

Ответ №4:

s — это просто указатель на что-то. Он не выделяет никакого пространства для хранения строки. В mingw32 вам повезло, что вы не перезаписали что-то критическое, в то время как в ideone он улавливает тот факт, что вы пишете там, где не должны быть.

Ответ №5:

Ну, вы вызываете неопределенное поведение.

Когда вы разыменовываете at *s = 65 , s не инициализируется и указывает на неопределенный адрес памяти, это локальная переменная, и поэтому она получает случайные данные. То же самое происходит со следующими строками.

Ideone не сбой был чистой удачей.

Ответ №6:

Когда вы объявляете char *s , для указателя не выделяется памяти. Либо вы можете выделить память, используя malloc или указывая s на массив, подобный char arr[3]; s = are .

Результаты не определены, если вы обращаетесь к неинициализированному указателю.