LINUX.ORG.RU

Шок от С. Как склеивать строки?

 


13

7

Осваиваю си. Всё шло хорошо пока внезапно не понадобилось склеить строки (константные и переменные). Покурил stackoverflow. Предлагают 2 варианта:

Первый - создать char buf[молись_чтобы_хватило] и делать str(n)cat/sprintf в этот buf.

Второй - использовать asprintf, который расширение, нестандарт и вообще.

Вопрос: как вы склеиваете строки? Может есть какая-нибудь общепринятая либа?

Простите за нубский вопрос

★★★★★

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

Ответ на: комментарий от i-rinat

А тут ты выделил 32 байта, из которых используешь только 16.

Я про выравнивание выше не зря сказал.

скоро ты так героически реализуешь часть GLib, только без тестов

У меня и так уже велосипедов полным-полно. Целый гараж. Но костыльную glib я использовать не собираюсь.

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

Во-во. Ну, подумаешь  — отстрелит ногу… Приделает костыль, и как новенькая!

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

зы: твой вариант вообще говнище, которое использовать в продакшене недопустимо. лучше уж c++ и std::string сразу, результат будет такое же говно, но с автоматическим управлением памятью.

upd: сорри, это был вариант Эдика :) не заметил что автор не ты.

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

Но ведь входной буффер надо строить, основываясь на размерах входных строк. Или имеется в виду сделать buf[1024] и работать с ним на протяжении всей програмы?

makoven ★★★★★
() автор топика

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

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

нет.

если строки не константы — то размер вычислить через strlen.

const char *str1, *str2; // пришли извне
size_t l1 = strlen (str1);
size_t l2 = strlen (str2);
char buffer[l1+l2+1];
memcpy (buffer, str1, l1);
memcpy (buffer+l1, str2, l2+1);
waker ★★★★★
()
Последнее исправление: waker (всего исправлений: 2)
Ответ на: комментарий от intelfx

Мой ответ был немного не об этом. С++ достаточно гибкий чтобы использовать STL не теряя ничего в эффективности. Просто например даже в данном случае это не дефолтный режим по понятным причинам. Но многие думают что «С++ тормозит»

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

char buffer[l1+l2+1];

А если l1+l2 == сотня килобайт? А ты на стеке выделяешь...

Вот меня матюкаешь за велосипеды, а сам-то не лучше!

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

для того, чтобы

использовать STL не теряя ничего в эффективности

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

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

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

Вот меня матюкаешь за велосипеды, а сам-то не лучше!

я вообще аццкий велосипедист :) ругал за кривой код, а не за велосипедизм.

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

Я про выравнивание выше не зря сказал.

Выравнивание не причём, просто malloc выделяет дополнительную память на служебные нужды.

Но костыльную glib

А где там костыли? Ты их там действительно видел? Тогда расскажи, мне интересно.

я использовать не собираюсь.

Океюшки.

i-rinat ★★★★★
()
Ответ на: комментарий от Eddy_Em

УМВР

А ты выдели буфер побольше, заполни мусором отличным от '\0' и освободи, а потом проделай то что делал, на 90% платформ в хелло ворде, у тебя перестанет работать:)

pon4ik ★★★★★
()

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

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

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

Например, написанный вручную примитивнейший вектор на стеке (в котором ещё и опущены {кон,де}структоры, т. к. заранее известно, что храниться будет plain old data) таки быстрее, чем std::vector с кастомным аллокатором.

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

Это вектор с заданным во время компиляции максимальным размером, который содержит все данные внутри себя (т. е. не производит дополнительных выделений памяти).

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

Нет, не array. Он не хранит текущий размер.

std::array — это

template <typename T, size_t N>
struct array {
    T data[N];
};

А вектор на стеке — это

template <typename T, size_t Nmax>
struct stack_vector {
    char data[Nmax * sizeof(T)];
    size_t N;
};

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

Медитировал над твоим кодом - так ничено и не понял)

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

Можно пример?

char *concat (char *buf, size_t bsize, char *s1, size_t s1size, char *s2, size_t s2size){

  return buf;
}
makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 1)

Вопрос: как вы склеиваете строки? Может есть какая-нибудь общепринятая либа?

Никак, они либо константны, либо в пайпах.

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

А если заменить на

typedef struct{
  size_t len;
  char *str;
} AnsiString;
typedef struct{  
  size_t len;
  wchar *str;
} WideString;
То почти $Билдер =)

А уж коли добавить поле кодировки, то и современная версия! =))

typedef struct{
  int CharSet;
  size_t len;
  char *str;
} AnsiString;
typedef struct{
  int CharSet;
  size_t len;
  wchar *str;
} WideString;

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

Говновик надел, бросайтесь.

# include <stdio.h>
# include <string.h>
# include <stdlib.h>
char* contact(char* str1,char* str2)
{
	char* new_str = (char*) malloc((strlen(str1)+strlen(str2))*sizeof(char));
	memcpy(new_str,str1,strlen(str1));
	memcpy(new_str+strlen(str1),str2,strlen(str2));
	return new_str;
}

int main()
{
	char* a = "Hello, ";
	char* b = "world!";
	char* c = contact(a,b);
	printf("%s\n",c);
}

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

Можно пример?

void concat (char *buf, size_t bsize, char *s1, size_t s1size, char *s2, size_t s2size){
    // тут воткнуть проверки на переполнение буфера
    memcpy (buf, s1, s1size);
    memcpy (buf+s1size, s2, s2size+1);
}

....

const char *s1 = "string1";
const char *s2 = "string2";
size_t l1 = strlen (s1);
size_t l2 = strlen (s2);
char buffer[l1 + l2 + 1];
concat (buffer, sizeof buffer, s1, l1, s2, l2);

для сокращения кода можно сделать макрос:

#define my_concat_macro(output,s1,s2)\
size_t l1 = strlen (s1);\
size_t l2 = strlen (s2);\
char output[l1 + l2 + 1];\
concat (output, sizeof output, s1, l1, s2, l2);

и вызывать

my_concat_macro (my_output_buffer, "hello, ", "world");
printf ("%s\n", my_output_buffer);

(сорри если где опечатался)

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

гемор с портируемостью

Портируемостью куда? Вроде с Linux и FreeBSD у неё неплохо.

с лицензией

Сюрприз. LGPL же. Или это как-то связано с политикой Apple Store и аналогичных площадок?

i-rinat ★★★★★
()
Ответ на: комментарий от makoven

То-есть, если я засуну этот код в функцию, мне придется в конце делать malloc чтобы вернуть склееную строку?

man strdup?

post-factum ★★★★★
()
Ответ на: комментарий от waker

Так намного понятнее. Спасибо

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

contact

Лучше с немецким акцентом. Kontakt!

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

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

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

так фиг там кто ответит <...>. Печалька

Это ещё ничего. Хуже когда советчики начинают генерировать бред в промышленных масштабах. Объяснять каждому, почему каждая конкретная реплика рассыпается при ударе о реальность, никаких сил не хватит.

i-rinat ★★★★★
()
Ответ на: комментарий от Eddy_Em

разумеется под эту структуру свою библиотеку функций.

А для устаревших

#define to_char(X) (X.str)
Как вариант, можно новый подтип ссылающийся сразу на str

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

Вроде с Linux и FreeBSD у неё неплохо.

на линуксах и бздях мир клином не сошелся.

Сюрприз. LGPL же.

на ряде платформ LGPL низзя. но это конечно не значит, что ты с этим столкнешься.

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

Сфигали?

Я в своих велосипедах хрюникод не использовал, не использую и не собираюсь использовать!

И веб-морды у меня на КОИ8. И ничего.

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

Протестуешь против проклятых пиндосов? Чому это в Фашингтоне символы по байту, а в Краснодаре по два?!

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

Вторая страница, а ведь до utf8 так и не дошли)

А чего, UTF-8 сложнее склеивать, чем KOI8-R? Разве что она некорректная, или там незакрытое bidi/ruby...

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

Так же

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

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

Всё проще: этот вопрос достаточно лёгкий для того, чтобы пол-ЛОРа считали себя в нём ыкспертами и не удерживались от того, чтобы изложить собственное Мнение™.

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

sizeof(char)

Ну чтобы наверняка, хотя да, логично тогда было бы вставить и в malloc()

нет \0 на конце строки

А нахера, если я вторую копирую строку вместе с \0?

нет пробелов после запятых

Нинужна(с)

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