LINUX.ORG.RU

Си, учебная задача, массив, указатели

 , ,


0

4

Не знаю какими словами спросить у поисковых систем. Код ниже выдает такой результат:

690165708 14754882 1571426279 748212300 546573552 710529569 1908956059 1365401208 1566297428 705403694

690165708 14754882 1571426279 748212300 925961456 909718834 875771960 359798784 1566297428 705403694

По замыслу, ряды чисел должны совпадать не только в начале и конце списка. Собственно вопрос в том, как так получаеться, что массив полученный в функцию main, частично отличаеться от того, что вызванная функция создала.

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

int* GenTwoDigitRand(int qTty);

int main(int argc, char **argv) {
	int const mySize = 9;
	int* myArray = GenTwoDigitRand(mySize);
	
	for (int i = 0; i <= mySize; ++i) {
		printf("%d ", myArray[i]);
	}
	
	return 0;
}

int* GenTwoDigitRand(int qTty) {	
	srand(time(NULL));
	int myArray[qTty];
	int myRand = 0;
	for (int n = 0; n <= qTty; ++n) {
		myRand = rand();
		myArray[n] = myRand;
	}
	int *p = myArray;
	
	for (int n = 0; n <= qTty; ++n) {
		printf("%d ", myArray[n]);
	}
	printf("\n");
	
	return p;
}

Подскажите что прочитать или с каким запросом лезть в поисковик. Спасибо.



Последнее исправление: hobbit (всего исправлений: 1)

Почему современные компиляторы таки убогие?

int* GenTwoDigitRand(int qTty) {	
	int myArray[qTty];
	int *p = myArray;
	
	return myArray;
}

Тут warning есть warning: function returns address of local variable [-Wreturn-local-addr]

А тут уже нет

int* GenTwoDigitRand(int qTty) {	
	int myArray[qTty];
	int *p = myArray;
	
	return p;
}

Зато код реордерить умеют (чтоб всё сломать), а отследить элементарный алиасинг не способны.

anonymous
()
Ответ на: комментарий от jpegqs

Давайте-ка вы покажете пример, где int будет быстрее unsigned.

Ты ж сам только что показал прототип такого примера

Си, учебная задача, массив, указатели (комментарий)

там надо чуть скорректировать: нижнюю границу не нулём сделать, со входа убрать плохие числа и вот он пример: unsigned делает на одно сравнение больше.

firkax ★★★★★
()
Ответ на: комментарий от anonymous

Почему современные компиляторы таки убогие?

gcc и clang открыты, кинь патчи. Это ж, видимо, не сложно, просто никто не догадался. Заодно оптимизацию можешь пофиксить, чтоб не ломалось ничего. Сам-то я и Dragon book не осилил, а то б я ух!

JaneDoe
()
Ответ на: комментарий от Jullyfish

printf("%d%с", myArray[i], i != mySize-1 ? ' ' : '\n');

Лишний if в цикле (да, экономия на спичках, но всё же), плюс, что важнее, хуже читается, нежели в оригинале.

Я б только puts("") на putchar('\n') заменил. Опять же, и нагляднее, и, возможно, чуточку эффективнее, лень искать реализации.

JaneDoe
()
Ответ на: комментарий от anonymous

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

Но если два лучших их представителя до сих пор это не ловят, хотя случай точно не редкий, думаю, не так всё тривиально.

JaneDoe
()
Ответ на: комментарий от JaneDoe

Эти люди тратят кучу сил и ресурсов на обсуждение стандарта годами и при этом неспособны договорится о банальном варининге в трёх строчках с одним присвоением без volatile и побочных эффектов.

Выглядит как катастрофа.

anonymous
()
Ответ на: комментарий от JaneDoe

хуже читается, нежели в оригинале.

Поэтому и написал:

но это уже на вкус и цвет

Но всё же плодить лишний пробел в конце строки – такое себе.

и, возможно, чуточку эффективнее, лень искать реализации.

Скорее всего в разных реализациях по-разному.

Jullyfish
()

Ну по проблеме уже ответили. Я видел. Хотелось бы выразить свои мысли тоже.

Вот для этого полезно покодить на ассемблере. Для понимания что такое локальная переменная, стек, вызов функции, соглашения о вызовах функций и т.д. и т.п.

Компилятор выскоуровневого языка скрывает, что происходит при вызове функции и возврате из неё. Скрывает, поскольку, программисты, когда кодили на асме, заметили, что делают одни и те же операции в этих двух случаях. Поэтому эти две рутинные операции можно было поручить компилятору и не париться.

Но «не париться» зашло слишком далеко. Новые поколения программистов уже не вдаются в эти детали, а зря. Там происходит очень важное таинство, объясняющее физический смысл локальных переменных.

Мне это напомнило крышечки во французском языке ^. Когда буквы из слов выпадали, французы, чтобы запомнить, что тут выпали буквы, ставили сверху крышечки. А потом уже никто не мог вспомнить, что там выпало, какие буквы, просто стали запоминать, что слово пишется с крышечкой. Изначальный вид слова уже никто не восстановит.

Также и тут. Поручили компилятору вызывать функции. И забыли как это делается. :-)


Если коротко, смотри. Исторически сложилось, что твоей программе отдана вся память. В современных ОС это уже конечно не так, но они это умело эмулируют, ты ничего не заподозришь. В начале идет твой код. Потом идут данные. Затем идет куча. Ну кучу ты еще не попросил, у тебя ее нет. Поэтому где-то здесь проходит граница между твоими данными и стеком.

А вот стек наоборот спускается сверху вниз, от старших адресов к твоим данным. Там далеко, так что, считай, он никогда до них не дойдет. Когда ты попросишь кучу, ты на самом деле подвинешь границу между данными и стеком. Но это ладно, не будем усложнять.

На стеке есть указатель, SP. Он так и называется Stack Pointer, это регистр процессора. Все адреса переменных в рамках текущей функции рассчитываются от текущего значения SP. А вот значение SP корректируется как раз при вызовах функций. При вызове функции – это называется преамбула. И обратная коррекция при возврате из функции я не помню как называется.

Поэтому переменные внутри функций, локальны. Потому что их адреса рассчитаны из местных значений Stack Pointer’a. Понимаешь?

Тут еще сложностей добавляет сама операционная система. Современные ОС защищенного режима со страничной организацией памяти, они могут уже отобрать страницу стека, которую ты использовал. Возможно в Dos бы твой код сработал. Но в современном мире уже слои абстракций, абстракция на абстракции и абстракцией погоняет.

hibou ★★★★★
()
Ответ на: комментарий от firkax

Ты ж сам только что показал прототип такого примера

Это был пример говнокода, который писать нельзя. Я уже упоминал что скорость полученная на UB нельзя считать ускорением. Если тот же пример переписать на unsigned, то проверок с границами массивов будет меньше (тоже давал пример).

Почему я против компиляторов спекулирующих на UB - скорость эту можно получить только на откровенно плохом коде. Обычно это старый легаси код, который работал правильно до их «оптимизаций». Но разработчиков компиляторов это не волнует. Им нужно выпускать новую версию компилятора и рисовать графики что производительность кода идёт вверх, и когда все способы уже исчерпаны - они начинают спекулировать на UB.

Также не все архитектуры умеют в чтение знаковых типов при чтении. Например в ARM (32-бит) до ARMv6 чтения всегда расширяют нулями. Поэтому char там по умолчанию используют беззнаковый для скорости (причем используют и в ARMv7 как наследие старой версии архитектуры). И «современный» Эльбрус не расширяет знаком при чтении, но я просил разработчиков это добавить.

Еще соглашение о вызове не всегда определяет что передаётся в старших битах, если число меньше размера указателя. Или может это компиляторы перестраховываются и всегда самостоятельно расширяют аргументы (x86, x86_64). Иногда соглашение о вызове определяет, но это зависит от архитектуры (и соглашения, у одной архитектуры могут быть разные соглашения о вызове). Например в mips64 и riscv64 - 32 бит значения передаются расширенные знаком (даже если это unsigned). Добиться чтобы компилятор точно не тратил время на на инструкции расширения - только используя long в качестве типа аргументов. Поэтому для MIPS и его наследника RISC-V лучше int.

Также разные 64-бит архитектуры по разному формируют результат 32-бит операции в 64-бит регистре.

  1. расширяют нулём (x86_64, arm64, e2k)
  2. расширяют знаком (mips64, riscv64, loongarch64)
  3. не трогают старшие биты (e2k в старом режиме)
  4. отсутствуют 32-бит операции, используется 64-бит операция (sparc64, power64)

P.S.: Robert C. Seacord, автор учебников по Си и участник ISO группы определяющей стандарт Си - советует использовать unsigned везде где можно, всё это из-за UB, и нападок на Си из-за этого UB со знаковыми целыми. Кого вы послушаете, его или тёмную личность с ЛОР советующую использовать int?

jpegqs
()
Ответ на: комментарий от hibou

При вызове функции – это называется преамбула. И обратная коррекция при возврате из функции я не помню как называется.

Про преамбулу не помню, но судя по описанию вы про пролог и эпилог.

Obezyan
()
Ответ на: комментарий от jpegqs

Давайте-ка вы покажете пример, где int будет быстрее unsigned.

А вы в чём-то правы - оказалось не так просто запровайдить реалистичный пример такого кода. Закинул удочку коллегам - посмотрим что скажут. А пока - смотрите какой треш и угар иногда генерится. Поменяйте там unsigned на int в цикле чтобы почувствовать разницу.

bugfixer ★★★★★
()
Ответ на: комментарий от Obezyan

Да, такие слова тоже припоминаю. И так, и этак встречалось наверное.

Вообще, конечно как заметил @mono, это все контент из старых свитков )))

Особенно в эру ИИ.

hibou ★★★★★
()
Ответ на: комментарий от hibou

Кажется, вся эта экономия – на спичках. По настоящему ускоряет вычисления алгоритм.

Согласен. Просто некоторые тут начали утверждать что int быстрее, и я привёл аргументы.

Спекуляции с UB в современных компиляторах - тоже экономия на спичках, больше вредит безопасности и открывает простор для критики языка, чем даёт производительности. Серьёзные проекты просто собирают код с опцией -fwrapv.

jpegqs
()
Ответ на: комментарий от jpegqs

некоторые тут начали утверждать что int быстрее, и я привёл аргументы.

Вы мне показали лишний register-to-register move который вы с большой вероятностью даже померять не сможете. Я вам показал миллионы лишних инструкций. И вы на голубой глазу продолжаете утверждать что беззнаковые быстрее, ага.

Серьёзные проекты просто собирают код с опцией -fwrapv.

А ещё есть -fno-strict-overflow. Но мне сейчас гораздо более интересно что вы серьёзными проектами называете, и за сколько из них вы головой отвечаете?

bugfixer ★★★★★
()
Ответ на: комментарий от bugfixer

какой треш и угар иногда генерится.

21474837 * 100 = 0x80000034, компилятор всё правильно соптимизировал.

Поменяйте там unsigned на int в цикле чтобы почувствовать разницу.

Это вырожденная бессмысленная задача. Она и для unsigned может решаться без цикла:

return limit >= 21474837 ? 21474837 : 0;

А для int компилятор прямо спекулирует на UB, что счётчик и результат умножения никогда не уйдут в минус. Если код оптимизируется за счёт UB - значит это плохой код, а не хороший компилятор.

jpegqs
()
Ответ на: комментарий от bugfixer

Я вам показал миллионы лишних инструкций.

На бессмысленном тесте с UB?

Тогда вот алгоритм, который на int с ненулевым значением работает бесконечное время, на unsigned за конечное. Я победил. Это не миллионы инструкций, это вечность.

int ctz_int(int x) {
	int a = 32;
	if (x) do a--; while (x += x);
	return a;
}

int ctz_unsigned(unsigned x) {
	int a = 32;
	if (x) do a--; while (x += x);
	return a;
}
ctz_int:
        test    edi, edi
        jne     .L3
        mov     eax, 32
        ret
.L3:
        jmp     .L3
ctz_unsigned:
        xor     eax, eax
        mov     edx, 32
        rep bsf eax, edi
        test    edi, edi
        cmove   eax, edx
        ret
jpegqs
()
Ответ на: комментарий от jpegqs

Если код оптимизируется за счёт UB

UB там появляется исключительно на больших значениях limit. И вот, не буду я их туда подсовывать. И хочу чтобы в моих use-cases код был максимально быстрым.

Это вырожденная бессмысленная задача.

Вы хотели пример где int быстрее, я предоставил. И он там пипец насколько быстрее. Я уверен что подумав и поигравшись подольше я бы это оформил это во что нибудь более осмысленное, например условие внутри цикла могло бы быть какой-нибудь лямбдой, итд.

Но интересней всего мне в данный момент остаётся ответ на вопрос «что вы серьёзными проектами называете, и за сколько из них вы головой отвечаете?» с которого вы ловко соскочить пытаетесь.

bugfixer ★★★★★
()
Ответ на: комментарий от bugfixer

Вы хотели пример где int быстрее, я предоставил. И он там пипец насколько быстрее.

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

int test_int(int limit)
{
    for (unsigned i = 0; i < limit; ++i) {
        if (int(i * 100) < 0)
            return i;
    }
    return 0;
}

И он там пипец насколько быстрее.

Даже если он в миллионы раз быстрее, я вам предоставил пример, тоже с UB, где int бесконечно медленнее. Что больше, миллионы или бесконечность?

jpegqs
()
Ответ на: комментарий от jpegqs

тоже с UB

В моём примере нет UB. А вот замедление из-за unsigned - есть, факт. И хоть обставьтесь клоунами - не трогает оно меня, от слова совсем. Только ваше бессилие и никчёмность демонстрирует.

bugfixer ★★★★★
()
Последнее исправление: bugfixer (всего исправлений: 2)
Ответ на: комментарий от bugfixer

В моём примере нет UB. А вот замедление из-за unsigned - есть, факт. И хоть обставьтесь клоунами - не трогает оно меня, от слова совсем. Только ваше бессилие и никчёмность демонстрирует.

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

jpegqs
()
Ответ на: комментарий от jpegqs

Патологических спорщиков надо банить, лучше навечно.

Вперёд. В гордом одиночестве остаться не боитесь? Или ещё лучше - в окружении вечно поддакивающих и со всем согласных болванчиков?

Их не интересует истина

Интересует. Только не в вашем её толковании.

они ляпнут глупость

Я вас умоляю - чья бы корова, что называется. Вы вон даже не до конца понимаете что такое UB. Исходя из вашей логики так signed вообще нельзя пользоваться.

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

Пипец. Не льстите себе - мне абсолютно всё равно что вы там думаете, как о программировании (до тех пор пока вы не озвучите за какие такие «серьёзные проекты» вы отвечаете - весомость вашего мнения для меня стремится к нулю), так и уж тем более о моей персоне. Да и люди которые начинают верещать «мама, он меня посчитал!» по поводу и без - особого уважения у меня не вызывают. Удачи вам, она вам походу ох как пригодится!

bugfixer ★★★★★
()
Ответ на: комментарий от jpegqs

У тебя с int-ом код, возможно, зависнет, но это как раз последствие UB. Но при этом видно что компилятор его очень сильно оптимизировал: убрал вообще все действия из цикла, за счёт предположения что UB нет.

Суть «ускорения», про которое пишут, как раз в том, что компилятор может выкинуть часть проверок, вычислив их во время компиляции в предположении что переполнения невозможны, и таким образом время, нужное на эти проверки, во время работы программы тратиться уже не будет. Если там действительно не случится переполнений, то программа продолжит работать корректно, но чуть быстрее. Если переполнения случатся, то часть выкинутых проверок могла оказаться нужной, и программа без них сломается - это и есть UB.

Я согласен с твоим заявлением что подобные оптимизации полезны в основном для плохого кода. В хорошем коде программист сам выкинет все проверки, которые посчитает нужным выкинуть (и при необходимости напишет рядом комментарий почему так сделано), а от компилятора ему будет нужно чтобы тот не разводил самодеятельность в этом плане (т.е. -fno-strict-overflow). Однако сказанного в предыдуем абзаце это не отменяет.

firkax ★★★★★
()
Ответ на: комментарий от bugfixer

Но мне сейчас гораздо более интересно что вы серьёзными проектами называете,

Линукс вроде как раз с wrapv компилируется.

Ну и очевидно мало кто захочет себе минное поле организовывать разрешая трактовать переполнение как UB.

firkax ★★★★★
()
Ответ на: комментарий от bugfixer

В моём примере нет UB.

В случае с int есть, и оно стреляет на значениях limit переполняющих i * 100, в варианте с unsigned UB нет вообще, т.е. это просто два семантически разных кода и компилятор отразил это, а не машинную разность между int uint

zurg
()
Ответ на: комментарий от zurg

Про машинную разность никто и не заявлял.

В случае с int есть, и оно стреляет на значениях limit переполняющих i * 100

Соответственно если такие limit туда не присылать - его не будет. А вот разница в скорости останется.

firkax ★★★★★
()
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int* GenTwoDigitRand(int qty);

int main(void) {
    const int mySize = 9;

    srand(time(NULL));  // инициализируем ГСЧ ОДИН раз

    int* myArray = GenTwoDigitRand(mySize);
    if (myArray == NULL) {
        printf("Memory allocation error\n");
        return 1;
    }

    for (int i = 0; i < mySize; ++i) {
        printf("%d ", myArray[i]);
    }
    printf("\n");

    free(myArray);  // освобождаем память
    return 0;
}

int* GenTwoDigitRand(int qty) {
    int* myArray = malloc(qty * sizeof(int));
    if (myArray == NULL) {
        return NULL;
    }

    for (int i = 0; i < qty; ++i) {
        myArray[i] = rand();
    }

    return myArray;
}

romanlinux ★★★
()
Последнее исправление: romanlinux (всего исправлений: 1)
Ответ на: комментарий от firkax

А вот разница в скорости останется.

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

ПыСы. Лично меня по настоящему разочаровывает другое: предел на котором происходит переполнение gcc прекрасно посчитал, а вот то что к нему вовсе необязательно подходить шажками по одному - нет. Перетру с коллегами на следующей неделе как Новый Год все отгуляют и в офис вернутся - глядишь и поправит кто.

bugfixer ★★★★★
()
Последнее исправление: bugfixer (всего исправлений: 2)

лучше используй

int two_digit_init(int* data, size_t data_sz){...}

// в main
...
data=(int *)calloc(data_sz, sizeof(int));

two_digit_init(data, data_sz);

free(data);

или создай two_digit_create() и two_digit_free(), и в идеале структуру two_digit_s

Так проще отделить ошибки при создании, от ошибок при инициализации

В учебном примере можно обойтись простым массивом без кучи: массивом на стеке ( при не очень большом размере), статическим (со словом static) или глобальным (вне main)

zudwa ★★
()
Ответ на: комментарий от bugfixer

А что, он должен был сгенерировать if(limit>21474837) return 21474837; else return 0;? Т.е. не просто убрать «лишние» действия, но ещё и выдумать дополнительное.

Ну, в плане нужности подобных оптимизаций (и этой, и той что заменяет всю функцию return 0 для int-а) согласен с уже озвученной позицией что помогают они только изначально плохо написанному софту, а для нормального кода - не нужны.

В частности, нормальный программист сам уберёт все лишние проверки если будет считать что тут невозможно переполнение. А раз он их не убрал - значит так надо, и компилятор не должен портить код.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от firkax

Неправильно сравнивать по скорости разные по поведению функции, за счёт разницы в поведении можно накрутить любую скорость в любую сторону. Пусть, вариант с int считаем правильным. Ему только вход надо расширить до полного int, убрав UB, например, так:

int test_int(int limit)
{
    if( limit < INT_MAX/100 ){
        for (int i = 0; i < limit; ++i) {
            if (int(i * 100) < 0)
                return i;
        }
    }
    return 0;
}

у второго варианта надо убрать ветки с кастами( int(unsigned) с возможным отрицательным результатом законен и компилятор не может это выбросить), из-за которых и появляется разница в поведении:

int test_uint(int limit)
{
   if( 0 < limit && limit < INT_MAX/100 ){
       for (unsigned i = 0; i < limit; ++i) {
           if (int(i * 100) < 0)
               return i;
       }
   }
   return 0;
}

https://godbolt.org/z/nYqcsYorP - вообще разницы нет

zurg
()
Ответ на: комментарий от zurg

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

И на всякий случай ещё раз повторю: тупой кодинг без понимания происходящего я осуждаю, и указанные оптимизации поэтому считаю ненужными. Но отрицать их существование и эффект я не буду.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от firkax

Т.е. не просто убрать «лишние» действия, но ещё и выдумать дополнительное.

Не дополнительное, а заменить while (i < limit) ++i; на i += limit; или хотя бы на i += min(limit, wrap_limit);. Почему нет? Хотелось бы, конечно, да.

В частности, нормальный программист сам уберёт все лишние проверки

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

Реально всё сводится к вопросам «а чего не хватает?» и «сколько усилий нужно приложить чтобы оно появилось?».

bugfixer ★★★★★
()
Ответ на: комментарий от bugfixer

Нельзя i+=limit делать, ты ж должен вернуть правильное i которое там где-то в середине может оказаться. а вот min() - это уже и есть дополнительное действие.

Рискну предположить что с шаблонами вам приходилось дело иметь совсем немного.

Верно, совсем немного. Но тема то не про С++.

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

С таким подходом не следует писать на Си. Си как раз для того, чтобы все технические детали были на виду и подконтрольны программисту.

firkax ★★★★★
()
Ответ на: комментарий от firkax

С таким подходом не следует писать на Си

Так я и не пишу, чего, собственно, никогда и не скрывал :)

Но тема то не про С++.

Ну, давайте всё что я до этого сказал считать прямым результатом проф-деформации, я не против :)

bugfixer ★★★★★
()
clang -fsanitize=address -g -o test_dummy test_dummy.c
./test_dummy

==57821==ERROR: AddressSanitizer: dynamic-stack-buffer-overflow on address 0x7ffc14dc15e4 at pc 0x55ad800785c4 bp 0x7ffc14dc1590 sp 0x7ffc14dc1588
WRITE of size 4 at 0x7ffc14dc15e4 thread T0
    #0 0x55ad800785c3 in GenTwoDigitRand /tmp/test_dummy/test_dummy.c:24:14
    #1 0x55ad800783da in main /tmp/test_dummy/test_dummy.c:9:17
    #2 0x7f55cd86a3fa  (/usr/lib64/libc.so.6+0x273fa)
    #3 0x7f55cd86a4aa in __libc_start_main (/usr/lib64/libc.so.6+0x274aa)
    #4 0x55ad7ff4e644 in _start (/tmp/test_dummy/test_dummy+0x2c644)

Address 0x7ffc14dc15e4 is located in stack of thread T0
SUMMARY: AddressSanitizer: dynamic-stack-buffer-overflow /tmp/test_dummy/test_dummy.c:24:14 in GenTwoDigitRand
Shadow bytes around the buggy address:
  0x7ffc14dc1300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffc14dc1380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffc14dc1400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffc14dc1480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffc14dc1500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7ffc14dc1580: 00 00 00 00 ca ca ca ca 00 00 00 00[04]cb cb cb
  0x7ffc14dc1600: cb cb cb cb 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffc14dc1680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffc14dc1700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffc14dc1780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffc14dc1800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==57821==ABORTING

Кто-то ошибся в количестве элементов массива и пишет в память, которая ему не принадлежит. Ну и возврат указателя на локальную переменную после всего этого.

LongLiveUbuntu ★★★★★
()
  1. Выход за пределы массива.
  2. Ошибки в scope.
  3. Надо не поисковики а LLM: chatGPT, Qwen, Grok, DeepSeek - взаимная проверка ответов, просьба ссылок. Поисковики - позавчера, навык работы с LLM - сегодня. Могут не все, кто не может - отстал.
  4. Если есть желания детально разбираться: http://stolyarov.info/books - там все разложено по полочкам. Программирование как Математику с кандычка не взять: надо выучить таблицу умножения, потом вынос за скобки, потом азы линейной алгебры, и только потом манат. Матан по форумным советам не выучить.
  5. codewars.com - каждый день по 25-30 задач, начиная с 8kyu. Практика, практика и еще раз практика, только практикой начинаешь чувствовать код. Если надо, конечно, многим - не надо.

-Терпение и труд - всё перетрут
-Нет ничего практичней чем хорошая теория

Это поговорки с моей кафедры, а я ей респектую. И LOR научил меня её любить, надо сказать «Спасибо» хору LOR «экспертов».

lbvf50txt
()
Последнее исправление: lbvf50txt (всего исправлений: 4)
Ответ на: комментарий от lbvf50txt

А, да Спасибо - без кавычек. Действительно LOR «эксперты» поменяли мое отношение к Вузу, улучшили его значительно. Показали, что означает отсутствие системного образования.

Сегодня, я так досконально проработал TCP механизм поддержания не прерывного потока данных через повторную посылку TCP сегментов, что под устал, чуть чуть. Но с TCP Header внутри IP дейтаграммы разобрался, а также с 32битными полями для порядкового номера начального октета (байта) сегмента у отправителя, и указание следующего порядкового номера октета ожидаемого к приему у получателя. Да! И TCP имеет два потока от клиента к серверу, и от сервера к клиенту - со своими порядковыми номерами, для одновременного разговора.

Механизм 3-way Handshake, ISN, Sequence Number (32 bit field), Acknowledgment Number (32 bit field), ACK and SYN flags. Все это разобрал. Так что, так. Но сначала, надо базис вышеописанный.

lbvf50txt
()
Последнее исправление: lbvf50txt (всего исправлений: 1)
Ответ на: комментарий от lbvf50txt

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

Obezyan
()