Принудительное изменение адреса массива(где указано имя массива) путем вызова по адресу. ошибка существует, но, похоже, она работает…?

#c

Вопрос:

Я смутно знаю, что имя массива может показаться типом указателя, но это не так.

(Я понял, что массив просто распадается на указатель, а не сам указатель. Пожалуйста, дайте мне знать, если мое понимание неверно)

Поэтому я подумал, что передача amp;arrayname1 и amp;arrayname2 в функцию ниже не может быть скомпилирована.

 void    swap(char **a, char **b)
{
        char *temp;
        temp = *a;
        *a = *b;
        *b = temp;
}
 

Но когда я компилирую файл test.c ниже, он выдает мне предупреждения, но функция работает.

 int     main()
{
        char a[] = "12";
        char b[] = "ab";


        swap(amp;a, amp;b);
        // char c[] = "asdb";
        printf("%s %sn", a ,b);

        return (0);
}
 

и результат был таким, как показано ниже,

 ab 12
*** stack smashing detected ***: terminated
Aborted
 

Затем я вставил бессмысленное утверждение, чтобы проверить, может ли исчезнуть сообщение «обнаружено разбиение стека». и сообщение исчезло.

 int     main()
{
        char a[] = "12";
        char b[] = "ab";


        swap(amp;a, amp;b);
        char c[] = "asdb";
        printf("%s %sn", a ,b);

        return (0);
}
 

Так что мои вопросы таковы..

  1. Возможно ли изменить адрес, на который указывает имя массива?
  2. Когда появляется сообщение «обнаружено разбиение стека» и что это значит? (Я погуглил это, но не смог найти связь между сообщением и кодами)
  3. Почему второй результат не приходит с «обнаруженным разбиением стека»?

(Пожалуйста, поймите, если есть какое-либо грубое выражение, потому что я плохо говорю по-английски.)

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

1. Ваше понимание массивов примерно верно. Проблема в том, что вы не можете изменить адрес объектов в памяти.

2. Содержимое указателя-это адрес, но содержимое ваших массивов-это символы, которые вы меняете местами. Это было бы ясно с более длинными строками.

Ответ №1:

Если вы вызываете свой компилятор в режиме, соответствующем стандарту, он должен вывести диагностическое сообщение для этого неправильного кода.

Многие компиляторы все равно продолжают компилировать неправильный код, если только вы не будете достаточно настойчивы, чтобы сказать им не делать этого.

Для этого проверьте документацию вашего компилятора. В GCC вы используете переключатель -pedantic или -pedantic-errors вместе с режимом соответствия ISO, таким как -std=c11 .


Невозможно изменить адрес любого уже существующего объекта, массивы не являются исключением. Код содержит нарушение ограничений (как вы указываете — несовместимый тип аргумента функции) и , следовательно, не является допустимой программой на языке Си, поэтому компилятор не обязан применять правила, применимые к допустимым программам. Следовательно, вы можете получить всевозможное неожиданное поведение.

Ответ №2:

  1. Нет. Место размещения массивов (не выделяемых динамически) определяется во время компиляции и не может быть изменено во время выполнения.
  2. Сообщение появляется при обнаружении разбиения стека. В этом случае swap запишите 4-байтовое или 8-байтовое (в зависимости от платформы, а также, возможно, другого размера) значение в переданные указатели, но переданные указатели на самом деле указывают на 3-байтовые массивы, поэтому происходит запись за пределы и вызывается неопределенное поведение.
  3. Возможно, добавление c поставило a и b достаточно далеко от важных данных (обратный адрес, например) и предотвратило его обнаружение неработающих данных.