C - Stati c массив символов против динамического c массив символов - PullRequest
0 голосов
/ 18 апреля 2020

Этот код компилируется с предупреждением, но печатает входную строку:

char staticArray[100];
scanf("%s",&staticArray);
printf("%s\n", staticArray);

Предупреждение: формат указывает тип 'char *', но аргумент имеет тип 'char (*) [100]' [-Wformat]

Этот код также компилируется с предупреждением, но выдает ошибку сегментации:

char* dynamicArray;
dynamicArray = (char*) malloc(sizeof(char)*100);
scanf("%s", &dynamicArray);
printf("%s\n", dynamicArray);

Предупреждение: формат указывает тип 'char *', но аргумент имеет введите 'char **' [-Wformat]

Я знаю, что оба не правы, но почему первый выводит строковое значение?

Ответы [ 2 ]

1 голос
/ 18 апреля 2020

почему первый выводит строковое значение, а второй дает segfault?

Что происходит в случае I:

Тип staticArray равен char [100], т. Е. Массив 100 char.
Тип &staticArray равен char (*)[100].
%s спецификатор формата в scanf() ожидает аргумент как указатель на начальный элемент массива char, то есть типа char *.

Вы передаете тип char (*)[100] в scanf(), следовательно, компилятор выдает предупреждение в этом операторе.

&staticArray дает вам указатель на массив типа char (*)[100], который численно 1034 * совпадает с базовым адресом массива.

Учтите это пример:

#include <stdio.h>

int main(void)
{
    char staticArray[100];

    printf ("staticArray: %p\n", (void*)staticArray);
    printf ("&staticArray : %p\n", (void*)&staticArray);

    return 0;
}

Вывод:

## ./a.out
staticArray: 0x7ffee4044a70
&staticArray : 0x7ffee4044a70

staticArray и &staticArray оба дают указатель на один и тот же адрес 1) , но их тип отличается . Вот почему, когда вы передаете &staticArray в scanf(), получая предупреждение во время компиляции из-за несоответствия типов, но когда вызывается scanf(), он обрабатывает этот указатель как char * и читает ввод и сохраняет результат в заданном месте. При печати позже она печатает строковое значение.

Что происходит в случае II:

Тип dynamicArray равен char *.
Тип &dynamicArray равен char **.
Итак, вы передаете char ** type в scanf(), который ожидает char * при использовании спецификатора формата %s. Следовательно, компилятор предупреждает об этом. Указатель &dynamicArray отличается от dynamicArray.

Рассмотрим этот пример:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char* dynamicArray;
    dynamicArray = malloc(sizeof(char)*100);
    if (dynamicArray == NULL) {
        exit(EXIT_FAILURE);
    }

    printf ("dynamicArray: %p\n", (void*)dynamicArray);
    printf ("&dynamicArray : %p\n", (void*)&dynamicArray);

    free(dynamicArray);
    return 0;
}

Вывод:

## ./a.out
dynamicArray: 0x7fd615401690
&dynamicArray : 0x7ffee7ab7ad0

dynamicArray и &dynamicArray оба даст другой указатель .

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

Когда вы передаете &dynamicArray в printf() с указателем формата %s, printf(), он получает доступ к этому адресу для записи строки символов и в итоге получает доступ к недопустимой памяти, что приводит к неопределенному поведению 2) . Следовательно, вы получаете segfault.


1) Массив автоматически преобразуется в указатель на свой первый элемент, но есть несколько исключений из этого правила (Стандарты C11 # 6.3.2.1p3):

  • Массив является операндом оператора sizeof.
  • Массив является операндом оператора _Alignof.
  • Массив является операндом & .
  • Массив - это строковый литерал, используемый для инициализации массива.

2) неопределенное поведение включает в себя его некорректное выполнение (либо сбой, либо генерирование без вывода сообщений) неверные результаты), или он, к счастью, может делать именно то, что и хотел программист

1 голос
/ 18 апреля 2020

Удаление оператора & в обоих примерах устранит предупреждения. Я не уверен, каково ваше предполагаемое поведение, но они, кажется, работают правильно после перемещения оператора &. Это связано с тем, что массивы по своей сути являются указателями на первый элемент массива, поэтому добавление & - это не то, что вам нужно.

Рабочие примеры (точно такой же результат для &):

char staticArray[100];
scanf("%s",staticArray);
printf("%s\n", staticArray);

и

char* dynamicArray;
dynamicArray = (char*) malloc(sizeof(char)*100);
scanf("%s", dynamicArray);
printf("%s\n", dynamicArray);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...