LINUX.ORG.RU

Правильно ли я организовал выделение памяти?

 


3

2

Здравствуйте! «Правильно» ли я выделяю код для для текстовых строк (*s)? Является ли такой способ «экономичным» для хранения массива текстовых данных?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct str_t {
	char     *s;
        double    e;
	int   a,b,c;
	long int  f;
} *pstr;
const int N=5;
char string_buf[80];

int main(){
pstr=(struct str_t*)malloc(N*sizeof(struct str_t));              
int i;
for(i=0;i<N;i++){
  scanf("%s",string_buf);		                                 
  pstr[i].s=(char *)malloc(strlen(string_buf)*sizeof(char));   
  strcpy(pstr[i].s,string_buf); 	                             
};

for(i=0;i<N;i++) free(pstr[i].s);
free(pstr);

return 0;
}
Все проверки опущены.

★★★★★

  • Не забывайте про NULL-байт в конце строк
  • sizeof(char) всегда == 1 в Си
  • кастовать void-пойнтер, который возвращает malloc, не нужно
rand ()

Явные преобразования типов не нужны; struct str_t вообще не нужна; для создания копии строки есть strdup; при выделении памяти под строку ты не выделяешь место под терминатор.

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

И какой же ты проверкой проверишь, что твой пользователь на stdio подаст в будущем?

kim-roader ★★ ()

pstr=(struct str_t*)malloc(N*sizeof(struct str_t));

pstr=(struct str_t*)calloc(N, sizeof(struct str_t));

scanf(«%s»,string_buf);
pstr.s=(char *)malloc(strlen(string_buf)*sizeof(char));
strcpy(pstr.s,string_buf);

scanf(«%ms», &pstr.s );

no-such-file ★★★★★ ()
Ответ на: комментарий от tailgunner

Что по этому поводу говорит man scanf?

Если тебе лениво посмотреть, то man scanf сообщает что %ms берет строку и динамически выделяет под неё память прямо в scanf.

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

scanf(«%ms», &pstr.s );

Ого, впервые вижу m в формате. Где про него почитать?

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

Если тебе лениво посмотреть, то man scanf сообщает что %ms берет строку и динамически выделяет под неё память прямо в scanf.

Точно, нашел в примере, но в описании форматирования не вижу.

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

Что по этому поводу говорит man scanf?

Если тебе лениво посмотреть

Мне не лениво. У меня в мане ее нет, и я спрашивал о том, когда m добавлен.

%ms берет [...]

Это вполне очвидно.

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

«адрес адреса»?

Всё правильно, ты передаёшь адрес указателя.

содержится адрес указателя

Эм, там у тебя вроде бы просто указатель, т.е. адрес строки.

no-such-file ★★★★★ ()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от tailgunner

когда m добавлен.

NOTES

The GNU C library supported the dynamic allocation conversion specifier (as a nonstandard extension) via the a character. This feature seems to be present at least as far back as glibc 2.0.

It is not available if the program is compiled with gcc -std=c99 or gcc -D_ISOC99_SOURCE (unless _GNU_SOURCE is also specified), in which case the a is interpreted as a specifier for floating-point numbers (see above).

Since version 2.7, glibc also provides the m modifier for the same purpose as the a modifier. The m modifier has the following advantages:

* It may also be applied to %c conversion specifiers (e.g., %3mc).

* It avoids ambiguity with respect to the %a floating-point conversion specifier (and is unaffected by gcc -std=c99 etc.)

* It is specified in the POSIX.1-2008 standard.

no-such-file ★★★★★ ()
Ответ на: комментарий от no-such-file

содержится адрес указателя

Эм, там у тебя вроде бы просто указатель, т.е. адрес строки.

да, верно. Спасибо, догнал!

int13h ★★★★★ ()

Что ты делаешь? Зачем все это? Это оверхед. Узнал размер, выделил память, таскай указатель. Все. Ну можешь простенький сборщик мусора сделать, чтоб не освобождать руками.

Все.

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

Может я ошибаюсь, но я хотел динамически выделить память под строки (в структурах).

-1-
Array of pointers:
[[pstr.s 0],[pstr.s 1],[pstr.s 2],[pstr.s 3],[pstr.s 4]]

Each pointers has a string adress
-2-
[pstr.s 0] ---------------> wwwwwwwww/0
[pstr.s 1] ---------------> wwwwwwwwwddddddds/0
[pstr.s 2] ---------------> xxxxxxxxxxxxxx/0
[pstr.s 3] ---------------> wwwwwwwww/0
[pstr.s 4] ---------------> wwwwwwwwwwwwwwwwwwwwww/0
Что-то такое

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

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

Я так не делал, честно. Ну, динамические строки пилил, но очень простые. Указатель и длина строки, и все.

Deleted ()
Ответ на: комментарий от Deleted
#include <stdio.h>

typedef struct{

	char s[200];
	int a,b,c;
    float ds;
    
} str1_t;

typedef struct{

	char *s;
	int a,b,c;
    float ds;
    
} str2_t;


int main(int argc, char **argv)
{
	
	printf("%d\n",sizeof(str1_t));
	printf("%d",sizeof(str2_t));
	return 0;
}

Экономия от необъявления количества элементов массива s дает экономию

s - str1_t - str2_t
байт, так?

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

Ну, разница в размере структур здоровая, да.

Но я советую копать в эту сторону:

struct String {
    char *s;
    int len;
}
...
struct MyStruct {
    String str;
    int a, b, c;
}
...
Понимаешь? Напиши как бы класс - строку и методы к нему. Т.е. структуру и функции к ней. И пихай такой унифицированный вариант везде, это удобно.

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

Именно. Все крупные проекты так и делают. В том же gtk своя реализация строк, если не ошибаюсь, ибо изучаю его столько же, сколько и фиксил панельку - часа 2.

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

Ну, я не говорю тебе что делать, я только советую.

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

Это будет больше велозаезд вникуда. Пока ты не обмазан фреймворком, который реализует все операции со своим навелосипеженным типом строки, ты все равно будешь пользоваться либсишными функциями. Кроме того, сишная строка имеет инвариант — конец при '\0', а len его размазывает и нарушает SPOT. Хранить стоит разве что size — размер последнего реаллока, чтобы знать, когда делать следующий.

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

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

в данном случае (псто#1) мой подход правильный? Т.е. память выделяю динамически на *s, а не S[N], и экономия S[N] - s байт, так?

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

Так. Правда это не *s экономия, а скорее s[n] идиотизм, за редкими исключениями. И если быть точным, средняя экономия считается как n/2-sizeof(void*).

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

Кстати если задача на экономию, то в структуре можно экономить один указатель, положив строку сразу за ней:

struct my {
    int bla;
    double bla2;
    char s[];
} *my;
my = malloc(sizeof(*my)+strlen(buf)+1);
my->s[0] = 0;
Правда реаллок отдельно уже не сделать, и вроде не очень стандартно, не помню, гугли variable length struct member или типа того.

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

Правда не факт, что аллокатор не сожрет профит на выравнивании, так что вот.

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

почему Вы считаете, что в первом посте оверхед? То, что структура имеет всего один указатель? Я имел ввиду метод хранения текстовых данных в массивах структур, где память динамически выделяется на размер введенной строки + нуль (), а не на изначально определенный массив символов S[N]), что дает экономию s - str1_t - str2_t. Может не ловко подал смысл - простите.

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

просто, как мне кажется, во многих примерах хранят в S[N], по крайней мере там, где видел, хотя много не смотрел =). Вот, и еще, возник у меня вопрос, а если модифицировать такую запись,то придется сдвигать область памяти (как в +, так и в - ), так? Это выгоднее по затратам чем держать поле S[N]?

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

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

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

просто, как мне кажется, во многих примерах хранят в S[N]

массив указателей на самом деле занимает 3.5%, потому не трогай его. Много места занимают хвосты строк, которые пихает аллокатор. Т.к. он не знает, будешь-ли ты двигать/уничтожать строки, или нет. Если НЕ будешь, то выдели Over9000 памяти, и выделяй строки вплотную одна к другой. Будет быстрее в разы и в разы экономнее.

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