Заполнение данной структуры происходит через специальный метод. который так же реализован чрез структуру SPLITTER, но это не суть важно. Метод проверен, отрабатывает верно и чисто. Для ясности приведу пример SPLITTER структуры
typedef struct
{
int colls_num; //number of substringschar **substrings; //substring values array
}SPLITTER;
Исходный код формирования структуры MAPPER вот такой (printf для теста. можно не обращать внимание):
Так вот. Суть в том, что при формировании структуры MAPPER на этапе формирования последнего value (то есть если всего у нас 4 элемента ИМЯ/ЗНАЧЕНИЕ ) возникает ошибка invalid fastbin entry (free): 0x0000000000c350f0 ***
То есть имя для 4 элемента формируется а значение нет.
Косяк где то вот тут:
else
{
if (i==2)
map.value=(char **)malloc(sizeof(char *)*j+1);
else
map.value=(char **)realloc(map.value,sizeof(char*)*j+1);
Хотел думать что проблема с выделением нового блока памяти, но в таких случаях обычно выдается segfault. В чем именно проблема может быть еще -я пока что понять не могу.
На всякий случай положил исходники самих обработчиков MAPPER и SPLITTER в отдельный файл и запихнул так же исходник с тестовым примером где проявляется ошибка (только пути к файлам исходников обработчиков поправьте, чтобы собралось). Буду благодарен за наводку.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Ovoshlook, Вы писали:
O>>Всем привет. реализую некое подобие MAP для C. С динамическим выделением памяти под поля name и value.
EP>1. Зачем C? EP>2. Для C есть GLib.
Хочется поизобретать велосипед это раз и Я не знал что есть GLib это два)
O>Хотел думать что проблема с выделением нового блока памяти, но в таких случаях обычно выдается segfault. В чем именно проблема может быть еще -я пока что понять не могу.
Проблема в том, что ты записываешь свои данные в область памяти, которую ты не выделял. Ну а вскрывается это не сразу, а собственно при других операциях с памятью, вроде того же вызова realloc.
Вообще, код ужасен.
Попробуй для начала его разбить на функции, убрать копипасту, дать переменным нормальные имена, а не безликие i/j/k.
Вот, например, если смотреть на имена, то почему у тебя j хранит длину строки в одном месте: int j=strlen(arr->substrings[i-1]);, а в другим месте — используется для определения длины массива указателей, которые ссылаются на эти строки: map.name=(char **)malloc(sizeof(char *)*j+1); ?
O>На всякий случай положил исходники самих обработчиков MAPPER и SPLITTER в отдельный файл и запихнул так же исходник с тестовым примером где проявляется ошибка
Молодец. Пусть там и лежат. Больше их не трогай, а возьми GLib :)
Здравствуйте, watchmaker, Вы писали:
O>Хотел думать что проблема с выделением нового блока памяти, но в таких случаях обычно выдается segfault. В чем именно проблема может быть еще -я пока что понять не могу.
Проблема в том, что ты записываешь свои данные в область памяти, которую ты не выделял. Ну а вскрывается это не сразу, а собственно при других операциях с памятью, вроде того же вызова realloc.
Ну как же не выделял если я ее тем же самым realloc выделяю для записи этой строки? Если не сложно- можно более подробно? пока что не понятно где я с выделением памяти просчитался?
Вот здесь:
else
{
if (i==2)
map.value=(char **)malloc(sizeof(char *)*j+1);
else
map.value=(char **)realloc(map.value,sizeof(char*)*j+1);
Если я встречаю первое значение для value я выделяю память через valloc для элемента массива, если же у меня знчение отличное от первого, значит я могу утверждать что память уже выделена и остается только ее расширить на необходимое количество байт.
Не понимаю пока что что не так в этом куске?
W>Попробуй для начала его разбить на функции, убрать копипасту, дать переменным нормальные имена, а не безликие i/j/k.
Ок. Принято
W>Вот, например, если смотреть на имена, то почему у тебя j хранит длину строки в одном месте: int j=strlen(arr->substrings[i-1]);, а в другим месте — используется для определения длины массива указателей, которые ссылаются на эти строки: map.name=(char **)malloc(sizeof(char *)*j+1); ?
Потому что выделяемая область памяти зависит от размера строки, который в свою очередь хранит переменная j
O>>На всякий случай положил исходники самих обработчиков MAPPER и SPLITTER в отдельный файл и запихнул так же исходник с тестовым примером где проявляется ошибка W>Молодец. Пусть там и лежат. Больше их не трогай, а возьми GLib
GLib не тяжеловата для таких, в общем то не сильно затратных операций? Может есть аналоги поменьше?
Здравствуйте, Ovoshlook, Вы писали:
W>>Вот, например, если смотреть на имена, то почему у тебя j хранит длину строки в одном месте: int j=strlen(arr->substrings[i-1]);, а в другим месте — используется для определения длины массива указателей, которые ссылаются на эти строки: map.name=(char **)malloc(sizeof(char *)*j+1); ? O>Потому что выделяемая область памяти зависит от размера строки, который в свою очередь хранит переменная j
map.name — это массив массивов, или по-другому — массив строк.
Количество элементов в массиве строк, зависит от количества строк, и не зависит от размера конкретной строки (то есть не зависит от j).
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Ovoshlook, Вы писали:
W>>>Вот, например, если смотреть на имена, то почему у тебя j хранит длину строки в одном месте: int j=strlen(arr->substrings[i-1]);, а в другим месте — используется для определения длины массива указателей, которые ссылаются на эти строки: map.name=(char **)malloc(sizeof(char *)*j+1); ? O>>Потому что выделяемая область памяти зависит от размера строки, который в свою очередь хранит переменная j
EP>map.name — это массив массивов, или по-другому — массив строк. EP>Количество элементов в массиве строк, зависит от количества строк, и не зависит от размера конкретной строки (то есть не зависит от j).
map.name=(char **)malloc(sizeof(char *)*j+1);
Так я выделяю для конкретного элемента массива. То есть не для количества строк в этом массиве, а для уже конкретной строки.
O>Так я выделяю для конкретного элемента массива. То есть не для количества строк в этом массиве, а для уже конкретной строки.
Хорошо, допустим ты так выделяешь память для конкретной строки. Тогда объясни, почему ты решил умножить j на sizeof(char*)? И почему у тебя тип результата является не указателем на строку, а указателем на массив указателей? И почему ты вообще присваиваешь результат переменной map.name?
O>Ну как же не выделял если я ее тем же самым realloc выделяю для записи этой строки?
Такая ошибка называется buffer overflow. Ну то есть она бы так называлась, если бы в твоей программы был смысл :) На самом деле, как уже повторно заметили, в коде безнадёжно перепутаны указатели на строки и массивы указателей.
O>>Так я выделяю для конкретного элемента массива. То есть не для количества строк в этом массиве, а для уже конкретной строки. W>Хорошо, допустим ты так выделяешь память для конкретной строки. Тогда объясни, почему ты решил умножить j на sizeof(char*)? И почему у тебя тип результата является не указателем на строку, а указателем на массив указателей? И почему ты вообще присваиваешь результат переменной map.name?
j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)
Так как переменная map.name массив массивов, то получается что делая realloc я добавляю память к массиву массивов, выделяя для элемента массива — строки, необходимое количество байт.
O>>Ну как же не выделял если я ее тем же самым realloc выделяю для записи этой строки? W>Такая ошибка называется buffer overflow. Ну то есть она бы так называлась, если бы в твоей программы был смысл На самом деле, как уже повторно заметили, в коде безнадёжно перепутаны указатели на строки и массивы указателей.
покажите конкретно пожалуйста- где у меня путаница с указателями. Я действитльно ее не вижу. я как бы не отрицаю вашей правоты и не убеждаю вас в вашей неправоте, мне просто искренне интересно где я накосячил (если накосячил) с выделением памяти и как оно по хорошему должно быть?
Здравствуйте, Ovoshlook, Вы писали:
O>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)
Давай по порядку. Из каких элементов состоит строка? Из указателей или из символов?
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Ovoshlook, Вы писали:
O>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)
EP>Давай по порядку. Из каких элементов состоит строка? Из указателей или из символов?
Здравствуйте, Ovoshlook, Вы писали:
O>>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций) EP>>Давай по порядку. Из каких элементов состоит строка? Из указателей или из символов? O>Строка состоит из символов
char — тип символа char* — тип указателя на символ sizeof(T) — возвращает размер типа T
Как посчитать размер строки, состоящей из символов, зная общее количество символов?
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Ovoshlook, Вы писали:
O>>>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций) EP>>>Давай по порядку. Из каких элементов состоит строка? Из указателей или из символов? O>>Строка состоит из символов
EP>char — тип символа EP>char* — тип указателя на символ EP>sizeof(T) — возвращает размер типа T EP>Как посчитать размер строки, состоящей из символов, зная общее количество символов?
умножить размер одного символа на общее количество символов в строке. sizeof(char)*<количество_символов>
Здравствуйте, Ovoshlook, Вы писали:
O>>>>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)
[...] O>умножить размер одного символа на общее количество символов в строке. sizeof(char)*<количество_символов>
Правильно, сравни с тем что было ранее, это одна из ошибок, на которую указал watchmaker.
Итак, зная размер строки X, мы можем выделить под неё буфер: malloc(X) — возвращает указатель на выделенный буфер размера X, либо нулевой указатель в случае fail.
Строка в C, обычно представляется как массив символов. Точнее как указатель на первый символ строки, который имеет тип char*.
Соответственно выделив буфер, сохраним его в переменной с правильным типом (а раз у нас C, то приведение типов не нужно):
char *string = malloc(X);
Далее вопрос, для чего тебе нужна эта новая строка (на данный момент содержащая мусор)?
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Ovoshlook, Вы писали:
O>>>>>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций) EP>[...] O>>умножить размер одного символа на общее количество символов в строке. sizeof(char)*<количество_символов> EP> EP>Правильно, сравни с тем что было ранее, это одна из ошибок, на которую указал watchmaker.
EP>Итак, зная размер строки X, мы можем выделить под неё буфер: EP>malloc(X) — возвращает указатель на выделенный буфер размера X, либо нулевой указатель в случае fail.
EP>Строка в C, обычно представляется как массив символов. Точнее как указатель на первый символ строки, который имеет тип char*. EP>Соответственно выделив буфер, сохраним его в переменной с правильным типом (а раз у нас C, то приведение типов не нужно): EP>
EP>char *string = malloc(X);
EP>
EP>Далее вопрос, для чего тебе нужна эта новая строка (на данный момент содержащая мусор)?
Здравствуйте, Ovoshlook, Вы писали:
EP>>Строка в C, обычно представляется как массив символов. Точнее как указатель на первый символ строки, который имеет тип char*. EP>>Соответственно выделив буфер, сохраним его в переменной с правильным типом (а раз у нас C, то приведение типов не нужно): EP>>
EP>>char *string = malloc(X);
EP>>
EP>>Далее вопрос, для чего тебе нужна эта новая строка (на данный момент содержащая мусор)?
O>Чтобы положить в нее свое значение
Откуда? из arr->substrings[i-1]?
То есть тебе нужно скопировать стоку, первый символ которой находится по адресу arr->substrings[i-1], в строку, первый символ которой находится по адресу string?
Как именно ты собрался это делать?
O>>Чтобы положить в нее свое значение
EP>Откуда? из arr->substrings[i-1]? EP>То есть тебе нужно скопировать стоку, первый символ которой находится по адресу arr->substrings[i-1], в строку, первый символ которой находится по адресу string? EP>Как именно ты собрался это делать?
Здравствуйте, Ovoshlook, Вы писали:
O>Исходный код формирования структуры MAPPER вот такой (printf для теста. можно не обращать внимание):
Такое впечатление, что этот код был переписан с паскаля. Индекс от 1 до colls_num включительно, проверка нечётности (!!!), и т.п.
Можно я его просто начисто перепишу?
Это если помещать каждую строку в отдельный блок.
А если хочется разместить все данные в одном блоке, чтобы mapper.name указывал на таблицу индексов, откуда ссылки вели бы на строки в этом же блоке, то НЕЛЬЗЯ делать realloc.
Потому что ты, тем самым, сбиваешь все указатели, которые были внутрь старого блока.
Здравствуйте, Ovoshlook, Вы писали:
O>>>Чтобы положить в нее свое значение EP>>Откуда? из arr->substrings[i-1]? EP>>То есть тебе нужно скопировать стоку, первый символ которой находится по адресу arr->substrings[i-1], в строку, первый символ которой находится по адресу string? EP>>Как именно ты собрался это делать? O>map.name[k]=arr->substrings[i-1];
Тут происходит копирование адреса, а не самой строки. Причём тот адрес который был раньше слева — затирается.
P.S. По всей видимости ты только начинаешь изучение C. Если в дальнейшем планируешь перейти на C++, то нет никакой необходимости сначала учить C — это только привьёт вредные привычки, которые к тому же порождают тормозной код.
Советую начать с книги Страуструпа — Programming -- Principles and Practice Using C++ (или на русском).
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Ovoshlook, Вы писали:
O>>Исходный код формирования структуры MAPPER вот такой (printf для теста. можно не обращать внимание):
К>Такое впечатление, что этот код был переписан с паскаля. Индекс от 1 до colls_num включительно, проверка нечётности (!!!), и т.п. К>Можно я его просто начисто перепишу? К>
К>Это если помещать каждую строку в отдельный блок. К>А если хочется разместить все данные в одном блоке, чтобы mapper.name указывал на таблицу индексов, откуда ссылки вели бы на строки в этом же блоке, то НЕЛЬЗЯ делать realloc. К>Потому что ты, тем самым, сбиваешь все указатели, которые были внутрь старого блока.
К>Делаем более чисто: К>
Огромное спасибо, хотя не совсем понятно почему нельзя использовать Realloc при выделении добавлении нового участка памяти к уже созданному массиву в динамике.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Ovoshlook, Вы писали:
O>>>>Чтобы положить в нее свое значение EP>>>Откуда? из arr->substrings[i-1]? EP>>>То есть тебе нужно скопировать стоку, первый символ которой находится по адресу arr->substrings[i-1], в строку, первый символ которой находится по адресу string? EP>>>Как именно ты собрался это делать? O>>map.name[k]=arr->substrings[i-1];
EP>Тут происходит копирование адреса, а не самой строки. Причём тот адрес который был раньше слева — затирается.
EP>P.S. По всей видимости ты только начинаешь изучение C. Если в дальнейшем планируешь перейти на C++, то нет никакой необходимости сначала учить C — это только привьёт вредные привычки, которые к тому же порождают тормозной код. EP>Советую начать с книги Страуструпа — Programming -- Principles and Practice Using C++ (или на русском).
Да. Я в курсе что передастся адрес на начало строки. Но собственно это и нужно- чтобы не плодить копии одной и той же строки. Да, с С я недавно познакомился и очень интересует именно работа с памятью, многопоточность, минималистичность и тому подобное. Естественно 1 блин комом, но поэтому сюда и обращаюсь, чтобы как не оставлять пробелов и понять недостающее. С С++ пока что не намерен связываться, хотя раньше писал дипломный проект на нем, точнее на Qt, все таки там очень высокоуровневое все, поэтому база не большая. За ссылку отдельное спасибо тем не менее.
Здравствуйте, Ovoshlook, Вы писали:
O>Да. Я в курсе что передастся адрес на начало строки. Но собственно это и нужно- чтобы не плодить копии одной и той же строки.
Ок, но если не нужны копии — тогда для чего выделять буфер размером со строку?
O>Да, с С я недавно познакомился и очень интересует именно работа с памятью, многопоточность, минималистичность и тому подобное.
Если сравнивать минималистичность самих языков, то тут безусловно лидирует C.
Если же сравнивать минималистичность кода, то C++ превосходит C. То есть сам код получается более лаконичный и быстрый (Это одна из основных фишек C++. Для многих это даже контринтуитивно, т.е. существует стереотип, что быстрый код должен быть dirty/hacky и super low-level, C++ как раз опровергает это).
Вот, например, что говорит Александр Степанов, создатель STL:
What do I mean when I say that an algorithm does not "impose any performance penalty"? In other words, how do you know that a generic algorithm is efficient? An algorithm is called relatively efficient if it's as efficient as a nongeneric version written in the same language, and it's called absolutely efficient if it's as efficient as a nongeneric assembly language version.
For many years, I tried to achieve relative efficiency in more advanced languages (e.g., Ada and Scheme) but failed. My generic versions of even simple algorithms were not able to compete with built-in primitives. But in C++ I was finally able to not only accomplish relative efficiency but come very close to the more ambitious goal of absolute efficiency. To verify this, I spent countless hours looking at the assembly code generated by different compilers on different architectures.
Здравствуйте, Ovoshlook, Вы писали:
O>Огромное спасибо, хотя не совсем понятно почему нельзя использовать Realloc при выделении добавлении нового участка памяти к уже созданному массиву в динамике.
Можно, но с пониманием.
realloc не просто увеличивает память, но и перемещает её, соответственно, все указатели внутрь старого блока становятся невалидными.
Кстати говоря, твой исходный код содержит характерные ошибки, показывающие существенное непонимание работы с памятью и со строками в Си.
После паскаля (или бейсика?) надо обязательно переучиваться, там всё совсем по-другому.
По задумке, хотелось добавить к массиву name ещё немножко памяти под очередную строку.
По факту, старый размер забыт, а память выделена только под неё.
Надо было писать
size_t bufsize;
char* buffer;
size_t count;
size_t* offsets;
char** strings; /* неправильно */
.....
size_t len = strlen(s);
buffer = realloc(buffer, (size+len+1)*sizeof(char)); /* изменили буфер */
offsets = realloc(offsets, (count+1)*sizeof(size_t)); /* изменили массивы индексов */
strings = realloc(strings, (count+1)*sizeof(char*));
offsets[count] = size; /* запомнили начало новой строки - её позицию... */
strings[count] = buffer+size; /* и непосредственно указатель на неё */
strcpy(buffer+size, s); /* скопировали строку внутрь буфера - в хвост */
count++;
size += len+1;
.....
/* получаем i-ю строку */char* t = buffer + offsets[i]; /* правильно */char* e = strings[i]; /* неправильно */
В чём проблема: после realloc смещения останутся теми же самыми (их надо будет отсчитывать от начала нового буфера), а вот указатели в массиве strings — все, кроме последнего, будут направлены в потолок.
Но в одном посте это всё рассказывать — никаких сил не будет.
Так что — бери старых добрых Кернигана и Ричи, и читай.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Ovoshlook, Вы писали:
O>>Огромное спасибо, хотя не совсем понятно почему нельзя использовать Realloc при выделении добавлении нового участка памяти к уже созданному массиву в динамике.
К>Можно, но с пониманием. К>realloc не просто увеличивает память, но и перемещает её, соответственно, все указатели внутрь старого блока становятся невалидными. К>Кстати говоря, твой исходный код содержит характерные ошибки, показывающие существенное непонимание работы с памятью и со строками в Си. К>После паскаля (или бейсика?) надо обязательно переучиваться, там всё совсем по-другому.
К>Например, К>
К>По задумке, хотелось добавить к массиву name ещё немножко памяти под очередную строку. К>По факту, старый размер забыт, а память выделена только под неё.
К>Надо было писать К>
К>size_t bufsize;
К>char* buffer;
К>size_t count;
К>size_t* offsets;
К>char** strings; /* неправильно */
К>.....
К>size_t len = strlen(s);
К>buffer = realloc(buffer, (size+len+1)*sizeof(char)); /* изменили буфер */
К>offsets = realloc(offsets, (count+1)*sizeof(size_t)); /* изменили массивы индексов */
К>strings = realloc(strings, (count+1)*sizeof(char*));
К>offsets[count] = size; /* запомнили начало новой строки - её позицию... */
К>strings[count] = buffer+size; /* и непосредственно указатель на неё */
К>strcpy(buffer+size, s); /* скопировали строку внутрь буфера - в хвост */
К>count++;
К>size += len+1;
К>.....
К>/* получаем i-ю строку */
К>char* t = buffer + offsets[i]; /* правильно */
К>char* e = strings[i]; /* неправильно */
К>
К>В чём проблема: после realloc смещения останутся теми же самыми (их надо будет отсчитывать от начала нового буфера), а вот указатели в массиве strings — все, кроме последнего, будут направлены в потолок.
К>Но в одном посте это всё рассказывать — никаких сил не будет. К>Так что — бери старых добрых Кернигана и Ричи, и читай.
Спасибо за разжевывания. Теперь более понятно. Обязательно прочту
EP>Ок, но если не нужны копии — тогда для чего выделять буфер размером со строку?
Наверное просто можно скопировать адрес строки в новый массив и все..ю Действительно...
O>>Да, с С я недавно познакомился и очень интересует именно работа с памятью, многопоточность, минималистичность и тому подобное.
EP>Если сравнивать минималистичность самих языков, то тут безусловно лидирует C. EP>Если же сравнивать минималистичность кода, то C++ превосходит C. То есть сам код получается более лаконичный и быстрый (Это одна из основных фишек C++. Для многих это даже контринтуитивно, т.е. существует стереотип, что быстрый код должен быть dirty/hacky и super low-level, C++ как раз опровергает это).
Ну помимо прочего, есть некое ПО написанное на С которое мне нужно бы расширить в будущем, поэтому и С. + Идеология классов меня не совсем устраивает, а если в С++ не использовать классы, то зачем использовать С++? (ну это как бы вопрос а не опровержение). Хотя конечно по поводу скорости (самого кода в итоге) — наверное это хороший аргумент в сторону С++, но как мне кажется хорошая программа на С не будет уступать С++ учитывая что С часто используют в программах, которые должны обрабатывать realtime потоки данных и подобные вещи. Но это уже риторика. Спасибо за подсказки и помощь. Буду делать и добиваться результата.