В вашем мышлении нет ничего плохого - вы абсолютно правы. Хорошая работа, теперь вы более квалифицированы в языке программирования Си, чем автор книги.
Книга бесполезна - 3-е пересмотренное издание, и в ней рассказывается об устаревшей версии C, написанной три десятилетия назад, с ужасно разбитыми примерами. Вы только что оказались счастливчиком с этим test4
. Размещение адреса первого элемента массива просто подавляет предупреждение в некоторых компиляторах, и массив оказался в правильной позиции в стеке и не перезаписывается. Но GCC 8.3 не одурачить, используя промежуточную переменную.
В функции
char *test4(char *ptr){
char buffer[10];
ptr = buffer;
strcpy(buffer, "testwert");
return ptr;
}
использование ptr
внутри функции никоим образом не влияет на указатель вне функции. Это работало в исходном примере, потому что ptr
был все еще , указывая на значение, возвращаемое из test3
, которое было выделено из кучи. Когда вы замените его на ptr = test4(ptr);
, вы получите совершенно неопределенное поведение, так как ptr
теперь указывает на переменную после ее времени жизни. И когда происходит неопределенное поведение, программа может сделать что-нибудь, в том числе ( C11 3.4.3p1 ):
[...] полное игнорирование ситуации с непредсказуемыми результатами [...]
с «непредсказуемыми результатами», включая возможность того, что он будет работать «как положено».
В предыдущем пункте бюллетеня указан один из вариантов:
- [Sie verwenden] einen beim Aufruf der Funktion als Аргумент übergebenen Puffer [...]
т.е. [Вы будете использовать] буфер, переданный в качестве аргумента в функцию . Для этой опции test4
должно читаться как
// use the **array** starting from *ptr
char *test4(char *ptr){
// use a **different** string here so that you can verify
// that it actually *works* (max 9 characters!)
strcpy(ptr, "testval 4");
return ptr;
}
или даже возможно
void test4(char *ptr){
strcpy(ptr, "testval 4");
}
с документацией о том, что перед вызовом этой функции ptr
должен указывать на массив не менее 10 char
с.