Почему char * c = NULL; вызывает ошибку в следующем коде? - PullRequest
0 голосов
/ 23 января 2020

Мое понимание:

  • char * c означает, что c ничего не указывает.

  • Когда я набираю «Hello World», c теперь указывает первый адрес «Hello World».

  • Должно быть напечатано H и e, но я получил ошибку «Ошибка сегментации: 11».

Может кто-нибудь, пожалуйста, просветите меня, почему и как char * c = NULL; вызывает ошибку?

Заранее спасибо!

#include <stdio.h>

int main(void)
{
    char * c = NULL;
    gets(c);
    printf("%c, %c\n", c[0], c[1]);
    return 0;

}

Ответы [ 2 ]

1 голос
/ 23 января 2020

char *c = NULL; объявляет указатель c, инициализированный NULL. Это указатель в никуда.

Напомним, указатель - это просто переменная, которая содержит адрес чего-то другого в качестве значения. Если вы обычно думаете о переменной, содержащей непосредственные значения, такие как int a = 5;, указатель будет просто содержать адрес, где 5 хранится в памяти, например, int *b = &a;. Прежде чем вы сможете использовать указатель для хранения данных в памяти - указатель должен содержать адрес (например, он должен указывать на) начала действительного блока памяти, к которому у вас есть доступ.

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

Самый простой способ - объявить массив символов и затем назначить адрес первому элементу указателю (массив преобразуется в указатель на первый элемент при доступе, так что простое назначение массива символов для вашего указателя хорошо). Например, с массивом buf, предоставляющим хранилище, и указателем p, содержащим адрес первого символа в buf, вы можете сделать:

#include <stdio.h>
#include <string.h>     /* for strcspn & strlen */

#define MAXC 1024       /* if you need a constant, #define one (or more) */

int main (void)
{
    char buf[MAXC],                         /* an array of MAXC chars */
        *p = buf;                           /* a pointer to buf */

    if (fgets (p, MAXC, stdin)) {           /* read line from stdin */
        p[strcspn (p, "\n")] = 0;           /* trim \n by overwriting with 0 */
        if (strlen (p) > 1) {               /* validate at least 2-chars */
            printf("%c, %c\n", p[0], p[1]); /* output them */
        }
    }

    return 0;
}

( note: strcspn выше просто возвращает количество символов в вашей строке вплоть до символа '\n', что позволяет вам просто перезаписать '\n', включенный fgets() с '\0' - который численно эквивалентен 0)

Пример использования / Вывод

$ ./bin/fgetsmin
Hello
H, e

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

1 голос
/ 23 января 2020

gets не выделяет память. Ваш указатель указывает на NULL, который не может быть записан, поэтому, когда gets пытается написать первый символ там, вы видите ошибку.

Решение:

  1. Используйте стек или глобальный массив (char c[1000];) или указатель на динамически выделенную память (char *c = malloc(1000);), а не указатель NULL.
  2. Никогда используйте gets, который по своей природе поврежден / небезопасен (он не может ограничить чтение, чтобы соответствовать размеру доступного буфера); используйте fgets вместо.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...