LINUX.ORG.RU

Конкатенация строк

 


2

2

Поскольку стандартные функции C убоги до невозможности — решил набыдлокодить свой велосипед для удобной конкатенации строк в количестве более двух:

char* str_concat(char *str_arr[])
	{
	char str[256] = "";
	for (int i=0; ; i++)
		{
		if (str_arr[i] == NULL) break;
		//printf("%s", str_arr[i]);
		strcat(str, str_arr[i]);
		}
	//printf("%s", str);
	char *out = (char*)malloc(sizeof(char)*(strlen(str)));
	strcpy(out, str);
	return out;
	}
Вызываю функцию примерно так:
char *arr[] = {"Строка1", "Строка2", …, "СтрокаN", NULL};
printf("%s\n", str_concat(arr));
Вопрос — как избавиться от фиксированного ограничения длины результирующей строки (char str[256])? Или есть варианты получше? На сишечке ничего сложнее хелловорлда не писал.

☆☆

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

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

И не забываем скрытые затраты на поиск нового места.

в смысле?

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

то я бы наверно печатал бы в выходной_файл

в glibc, насколько я знаю, это другой способ realloc (скорее всего это и есть файл отмапленный в память).

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

ага.

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

Сто слов разного снега рулят и педалят

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

Можно и без цикла, просто проверять размер буфера и при переполнении делать realloc на 2*size например. Если жалк память, то в конце делать shrink до результирующего размера.

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

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

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

Мы же не будем разводить тут детсад и придумывать какие-то странные примеры, чтобы потом на них строить странные метафоры? IRL бывает и строка, и абзац, и война и мир. Естественно, зная, что максимальный предел сравнительно небольшой, стоит выделить псевдостатический буфер. Я лишь показал, что независимо от размера дырок в куче ты имеешь немалые шансы попасть на пару реаллоков вместо одного, и что рандомно-статистически это дороже, чем сразу посчитать длину. И все это на фоне рандомной производительности. Скрытые затраты реаллока вообще неочевидны без знания деталей реализации стандартной библиотеки.

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

даже с удвоением размера O(nlogn) вместо O(n)

почему вообще заморачиватся с выделением памяти а не

#include <unistd.h>
void main(int c,char *str_arr[]){
	while(--c){
		++str_arr;
		while(**str_arr)write(1,(*str_arr)++,1);
	}
}

?

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

Можно ловко жонглируя границами все сделать на лету и за один проход, но во-первых забибикаешься +1/-1 баги ловить, а во-вторых это оптимизация в никуда, т.к. выход заранее неизвестен и зависит от таких факторов, как: фрагментация, какого типа аллокатор реализован в системе, на какие паттерны он рассчитан.

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

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

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

зачем считать вообще считать - «операционнка» под капотом нужные стратегии держит.

челу нужно сливать строки - строки сливаются.

замапить файлы и недумай про малоки лично.

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

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

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

если ровно той общьности «из указателя на массив указателей на нуль-терминированные последовательности байт получить указатель на нультерминированную последовательность» то достаточно однократного прохода по исходным данным

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

задача поставленна общая.

чел не хочет наперёд указывать какой максимальный размер ИТОГОВОЙ строки.

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

Вообще речь о том, что посчитал-выделил это все равно O(n), зачем при этом обмазываться всякими O(n*log2(random()) — непонятно. Да ну вас.

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

Ты мне уже весь мозг сломал своими марианскими уровнями вложенности. Зафрендил.

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

конечно при подсчёте сохраняется O(n) константа в два раза из за на проход больше чем читаем-пишем , и зачем самому выделять? если операционка для этого в том числе и написана.

qulinxao ★★☆
()

char str[256] = "";

1. Это лютый пипец в данном случае.

2. Кто вам запретил сделать strlen для всех подстрок и один malloc?

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

Тебе предлагают два цикла: в одном ты длинну высчитываешь и выделяешь память под результат, а во втором уже строки соединяешь.

Правильное решение.

С realloc можно и одним циклом обойтись :)

Так делать не нужно.

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

И чем оно принципиально отличается от strcat? Всё равно только два аргумента умеет.

Не нужно каждый раз пробегать по строке в поисках ее завершения.

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

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

реализуеш у себя прокси и вуаля функция получает набор строк и выдаёт указатель на строку. - без всякой с твоей стороны «раздражения » битиков/байтиков на тему сколько памяти и какой и откуда брать.

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

реализуешь у себя прокси

так тред, по сути, о том как этот прокси должен выглядить. Тут ты просто делаешь итерацию по строкам и натравливаешь функцию (типа map(f, iter) в функциональщине). А нужно-то представить несколько разрозненных строк в виде непрерывного куска байтов (если я правильно понял). Или вы уже о чём-то другом спорите?

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

ну вот и есть предложение перестимить этот поток (байт*\null)* в (байт*\null) через open_memstream() Конкатенация строк (комментарий) что наверно самый идеальный вариант в смысле безбажности.

или через asprintf ( но тут вылазии явное logN при слиянии строк)

- когда же в open_memstream (надо конечно реализацию смотреть может быть 1 копирование делание списка чанков и при флуше 2ое копирование в непрерывный блок.

имхо имховое но через open_memstream (спасибо anonymousу)(или аналог.функцию) - хорошо , что нет явного обмазыванию памяти - ибо нефиг.

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

возрадуйся ТС

#include <stdio.h>
void main(FILE* _,char *str_arr[]){
	char *ptr;size_t size;
	FILE *out;
	out=open_memstream(&ptr,&size);//no error handling :)
	while(*++str_arr){
		fprintf(out,"%s",*str_arr);//no error handling :)
	}
	fclose(out);
	//return ptr;//for tc what he wonna
	printf("%s",ptr);
}
qulinxao ★★☆
()
Ответ на: возрадуйся ТС от qulinxao

Так вот и вопрос как open_memstream устроен внутри :). Т.е. вопрос про алгоритм, а не «где взять готовое решение». Я так понимаю этот пример похож на конкатенацию с realloc в цикле.

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

не не не Дэвид блэйн

поскольку стандартные функции C убоги до невозможности — решил набыдлокодить свой велосипед для удобной конкатенации строк в количестве более двух:
char* str_concat(char *str_arr[])

пример использования:

char *arr[] = {«Строка1», «Строка2», …, «СтрокаN», NULL};
printf(«%s\n», str_concat(arr));

и собственно вопрос:

Вопрос — как избавиться от фиксированного ограничения длины результирующей строки (char str[256])? Или есть варианты получше? На сишечке ничего сложнее хелловорлда не писал.

ответ :

#include <stdio.h>
char* str_concat(char *str_arr[]){
	char *ptr;size_t size;
	FILE *out;
	out=open_memstream(&ptr,&size);//no error handling :)
	while(*++str_arr){
		fprintf(out,"%s",*str_arr);//no error handling :)
	}
	fclose(out);
	return ptr;
}

ровно делает то ,что тс возжелал - то что юзает библиотеку ну и чё :)

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

Я лишь показал, что независимо от размера дырок в куче ты имеешь немалые шансы попасть на пару реаллоков вместо одного, и что рандомно-статистически это дороже, чем сразу посчитать длину.

проблема в том, что IRL длинна может измениться. Т.е. ты выделил 3+10+4 байта, но тут ВНЕЗАПНО надо ещё 7. Можно сразу выделить 32(2⁵) байта, а не 17, да и вообще всегда выделять 2^N памяти, а если её недостаточно - удваивать. Эта стратегия иногда лучше(а иногда хуже), чем выделять точно столько, сколько нужно.

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

Вообще речь о том, что посчитал-выделил это все равно O(n), зачем при этом обмазываться всякими O(n*log2(random()) — непонятно.

можно сделать функцию append, которая работает как strcat, только ещё и выделяет память (или делает realloc). Но если делать realloc скажем на 1 байт, то это очень долго.

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

IRL длинна может измениться. Т.е. ты выделил 3+10+4 байта, но тут ВНЕЗАПНО надо ещё 7
Эта стратегия иногда лучше(а иногда хуже), чем выделять точно столько, сколько нужно.

Да, такое сплошь и рядом. То malloc() меньше чем нужно выделит, то strcpy() больше скопирует, чем strlen() вернул. Настало время увлекательных историй от доктора?

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

как избавиться от фиксированного ограничения
Или есть варианты получше?

ровно делает то ,что тс возжелал
то что юзает библиотеку ну и чё :)

Если смотреть на задачу, как «надо решить щас и не париться», то твое решение вполне обосновано. Надо только принять во внимание тот факт, что ты предлагаешь использовать нихрена непортабельный open_memstream, который черт его знает как себя ведет «под капотом». При переходе на систему с другой стандартную библиотеку, программа: А) не соберется, Б) будет подтормаживать без возможности что-то исправить, В) будет работать приемлемо. Естественно это все теория, я тоже за простоту, только по строкам кода все предложенные решения примерно одинаковы.

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

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

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

То malloc() меньше чем нужно выделит, то strcpy() больше скопирует, чем strlen() вернул. Настало время увлекательных историй от доктора?

нет. просто анонимус опять нажрался.

Что, если ты склеил 10 строчек, то приклейка к ним одиннадцатой - невозможное событие? Если прочитал из файла /dev/stdin 123 байта, то 124й уже никогда не прочитаешь?

Все события в твоей реальности допускают применения strlen(), и после этого никогда не растут?

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

А, не заметил, что open_memstream() размер вычисляет, снимаю вопрос.

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

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

ответ есть выше:

1. посчитать длину всех строк S

2. выделить S+1 байт

3. скопировать все строки в память (2)

4. размер строки равен S

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

Внутри одной моей фнукции — только по царскому велению, т.е. по моему хотению.

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

Зачем делать в два этапа (10, потом 11-я), если можно сделать в один? Если буферизация естественный процесс, данные надо оставлять в разобранном виде, пока не станет видна граница пакета, и только потом собирать, оставив хвост следующему пакету.

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

Зачем делать в два этапа (10, потом 11-я), если можно сделать в один?

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

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

т.е. ты предлагаешь наделать Over9000 кусков скажем по 50 байт, а потом сливать их в один? Вариант возможный, но я не думаю, что он экономичнее 7..8 realloc'ов. (50*2⁸ == 12800)

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

hehehe при замене заголовка с main на str_concat нужно менять прединкремент в вайле на постинкременте в принтфе ибо массив на 1 элемент меньше :)

зы. вывод ТС набрасывал :)

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

ну и ограничение вызова последняя строка в списки указатель на null

либо ввернуть счётчик вывалившийся при переносе str_concat->main->str_concat

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

Вы предлагаете памятью обмазыватся?

. исходно я предлагаю сделать печать(форматную) всех строк в поток и выдача указателя на строку прочитаную из этого потока.

какая конкретно реализация - зависит от насколько частоиспользуемая библиотека билдится.

прамая реализация - это что ?

вы допускаете использовать в прямой реалзации штатный менеджер (дин)памяти?

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

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

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

дилемма : что использовать из уже имеющегося , а что реализовывать с чистого листа.

имхо по KISS-принципу кинуть всё в pipe(unix)_[chanel с предобразование последовательности последовательностей в последевательность(golang)] и извлечь как одну сущность

обще чем опиратся на malloc.

обдумайте эту шутку http://www.gnu.org/fun/jokes/helloworld.html

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

дилемма : что использовать из уже имеющегося , а что реализовывать с чистого листа.

Что в одном случае, что в другом - нужна реализация. Ваш вариант костыльный и тормозной. Вероятно он хорош где то еще, но явно не в случае ТСа.

andreyu ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.