Правильное использование malloc

Я пытаюсь поместить мой путь к каталогу в строковую переменную, например так:

int main(int ac, char **av)
{
  char*dir;

  if(ac > 2)
    {
      dir = malloc(sizeof(*dir) * 512);
      getcwd(dir, sizeof(*dir));
      printf("dat dir is:\n");
      printf("%s\n", dir);
    }
}

Я получил печатный бланк, но когда я делаю что-то подобное

int main(int ac, char **av)
{
  char dir[512];

  if(ac > 2)
    {
      // dir = malloc(sizeof(dir) * 512);                                                                
      getcwd(dir, sizeof(dir));
      printf("dat dir is:\n");
      printf("%s\n", dir);
    }
}

это напечатано правильно, почему? Разве мой первый malloc не предполагает превращение моей переменной в dir[512]

4 ответа

Решение

В

getcwd(dir, sizeof(*dir))

sizeof производит 1, потому что *dir относится к одному char, Это не то, что вы хотите. Если вы замените это на 512, все должно работать нормально.

Идиоматическое кодирование будет примерно таким:

int main(int ac, char **av)
{
  const int buf_size = 512;
  char *dir;

  if(ac > 2)
    {
      dir = malloc(buf_size);
      getcwd(dir, buf_size);
      printf("dat dir is:\n");
      printf("%s\n", dir);
    }
}

Примечание умножение на sizeof(*dir) не работает, потому что он всегда возвращает 1. То есть malloc выделяет в единицах char, Так что я опустил no-op.

Это связано с массивами, указателями и значением sizeof,

char dir[512];
sizeof(dir);

Это запрашивает размер массива, который в этом случае sizeof(char) * 512 -> 512,

char *dir;
sizeof(dir);

Это запрашивает размер указателя, который в данном случае sizeof(char *) -> 4 или же 8

char *dir;
sizeof(*dir);

Это странная конструкция. Я действительно не чувствую себя комфортно с этим. Так как dir не было инициализировано разыменование dir это повод для беспокойства. Но я думаю, что компилятор работает здесь правильно, что в данном случае sizeof(char) -> 1,

При работе с указателями, вы должны носить с собой размер, который вы выделили.

char*dir;
if(ac > 2)
{
    dir = malloc(sizeof(char) * 512);
    getcwd(dir, sizeof(char) * 512);
    printf("dat dir is:\n");
    printf("%s\n", dir);
}

Правильный ответ ™ немного сложнее.

if (ac > 2)
{
    size_t size = 512;
    char *buf = malloc(size);
    char *dir = getcwd(buf, size);

    while (dir == NULL && errno == ERANGE)
    {
        size *= 2;
        buf = realloc(buf, size);
        dir = getcwd(buf, size);
    }

    printf("dat dir is:\n");
    printf("%s\n", dir);
    free(buf);
}

Во-первых, я бросаю sizeof(char), В С, sizeof(char) определяется как 1так что это избыточно. Далее установите dir в качестве возвращаемого значения getcwd(3) и держите буфер данных отдельно. Обязательно проверьте возвращаемое значение, если getcwd(3) возвращается NULL а также errno является ERANGE затем buf был недостаточно велик. В моем примере я удваиваю размер буфера перед попыткой getcwd(3) снова. Наконец, не забудьте освободить buf,

Здесь я не проверяю возвращаемое значение malloc(3) или же realloc(3), Это потому, что я чувствую, что в этом примере нет смысла. Если я не могу определить размер пути, моя программа будет зависать независимо от того, что я делаю.

Всякий раз, когда вы динамически выделяете память, всегда проверяйте возвращаемое значение из calloc, malloca и realloc, поскольку возвращаемое значение указывает, что память выделена успешно или нет. Здесь вышеупомянутый первый ответ хорош, и проверить возвращаемое значение всегда полезно.

Меньше вещей, которые могут пойти не так, если вы поместите размер в переменную на ранней стадии, а затем используете это:

 {
      const sizeof_dir = sizeof (* dir) * 512;
      dir = malloc (sizeof_dir);                                                                
      getcwd (dir, sizeof_dir);
      printf ("dat dir is: \ n");
      printf ("% s \ n", dir);
    }

Что убило тебя было getcwd(dir, sizeof(*dir))где размер был еще 1.

Другие вопросы по тегам