Форум программистов, компьютерный форум, киберфорум
Наши страницы
C для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.80/5: Рейтинг темы: голосов - 5, средняя оценка - 4.80
Rexer
165 / 164 / 46
Регистрация: 10.10.2010
Сообщений: 725
1

Динамическое выделение памяти в строках

17.11.2012, 16:26. Просмотров 984. Ответов 19
Метки нет (Все метки)

Программа должна сцепить 3 строки вместе,для этого я написал свою функцию myStrcat(); ,которая динамически ДОвыделяет память и сцепляет две строки.
Сначала мы выделяем память под первую строку,копируем ее туда,дальше пользуемся нашей функцией.Но!
Возникла такая проблема: программа работает корректно,только при условии,что в самом начале я выделил 9 байтов или больше,хотя первоначальная строка,которую я копирую всего 5!А дальше по идее должно все выделиться realloc-ом,но почему то не работает,если выделять меньше 9 в malloc();
Почему?
Заранее спасибо за ответ!
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
void myStrcat(char str1[], char *str2);
 
int main()
{
    char *str1;
    char *str0 = "All ";
    char *str2 = "Cops are ";
    char *str4 = "bastards";
    str1 = (char*)malloc(9);
 
    strcpy(str1,str0);
 
    myStrcat(str1,str2);
    myStrcat(str1,str4);
    printf("%s length is : %d",str1,strlen(str1));
    return 0;
}
void myStrcat(char* str1, char *str2)
{
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    char *stpos;
    char *nextPos;
    stpos = str1;
 
    nextPos = (char*) realloc(str1, len1 + len2 + 1);
    str1 = nextPos;
 
    str1 += len1;
 
    while(*str2)
    {
        *str1 = *str2;
        str1++;
        str2++;
    }
    *str1 = '\0';
    str1 = stpos;
}
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
17.11.2012, 16:26
Ответы с готовыми решениями:

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

Динамическое выделение памяти в С
Ввести num - количество массивов. Ввести размерность очередного массива и его...

Динамическое выделение памяти в Си
Пожалуйста, расскажите или покажите на примере, как выделить динамическую...

Динамическое выделение памяти
Всем привет! Решил вот разобраться с выделением памяти.В общем выделяем память...

Динамическое выделение памяти
Здравствуйте! Хочу часть кода,где динамически выделяется память под массив: ...

19
polyaKIDze
63 / 63 / 20
Регистрация: 16.07.2012
Сообщений: 147
17.11.2012, 18:34 2
Rexer, почему вы не пользуетесь sizeof()? Я не уверен, что под символ типа char выделяется ровно 1 байт. Точнее сколько выделяется под строку символов.
1
Rexer
165 / 164 / 46
Регистрация: 10.10.2010
Сообщений: 725
17.11.2012, 20:46  [ТС] 3
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
void myStrcat(char str1[], char *str2);
 
int main()
{
    char *str1;
    char *str0 = "All ";
    char *str2 = "Cops are ";
    char *str4 = "bastards";
    str1 = (char*)malloc(5*sizeof(char));
 
    strcpy(str1,str0);
 
    myStrcat(str1,str2);
    myStrcat(str1,str4);
    printf("%s length is : %d",str1,strlen(str1));
    return 0;
}
void myStrcat(char* str1, char *str2)
{
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    char *stpos;
    char *nextPos;
    stpos = str1;
 
    nextPos = (char*) realloc(str1, (len1 + len2 + 1)*sizeof(char));
    str1 = nextPos;
 
    str1 += len1;
 
    while(*str2)
    {
        *str1 = *str2;
        str1++;
        str2++;
    }
    *str1 = '\0';
    str1 = stpos;
}
Результат тот же,если вас это смущает
char занимает 1 байт
В чем ошибка,кто подскажет?
Заранее всем спасибо за помощь!
0
polyaKIDze
63 / 63 / 20
Регистрация: 16.07.2012
Сообщений: 147
17.11.2012, 21:12 4
Динамическое выделение памяти в строках
Динамическое выделение памяти в строках

Потестил код в VS. Переключаться на unix лень.
Я мог и стормозить, но 5 байт хватило.

Не по теме:

Не спрашивайте, почему factorial.exe )

1
g_u_e_s_t
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
17.11.2012, 21:52 5
Один вопрос, а что будет с программой если realloc() выделит новый блок вместо увеличения размера str1?
1
Rexer
165 / 164 / 46
Регистрация: 10.10.2010
Сообщений: 725
17.11.2012, 22:43  [ТС] 6
Потестил код в VS. Переключаться на unix лень.
Я мог и стормозить, но 5 байт хватило
Т.е у вас все заработало нормально?

Добавлено через 54 секунды
Цитата Сообщение от g_u_e_s_t Посмотреть сообщение
Один вопрос, а что будет с программой если realloc() выделит новый блок вместо увеличения размера str1?
Мне хочется,чтобы размер str1 увеличивался динамически,можно,конечно,и блоки новые выделять,а старые чистить
0
polyaKIDze
63 / 63 / 20
Регистрация: 16.07.2012
Сообщений: 147
17.11.2012, 22:44 7
Rexer, я не зря прикрепил скриншоты. На первом дал 2 символа, ровно столько из "All " туда и поместилось, на втором - все ОК.
0
g_u_e_s_t
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
17.11.2012, 22:56 8
Цитата Сообщение от Rexer Посмотреть сообщение
Мне хочется,чтобы размер str1 увеличивался динамически,можно,конечно,и блоки новые выделять,а старые чистить
Я не к тому писал Внимательно прочитайте как работает realloc(). Подумайте что случиться если nextPos != str1
1
Rexer
165 / 164 / 46
Регистрация: 10.10.2010
Сообщений: 725
18.11.2012, 02:20  [ТС] 9
Цитата Сообщение от polyaKIDze Посмотреть сообщение
Rexer, я не зря прикрепил скриншоты. На первом дал 2 символа, ровно столько из "All " туда и поместилось, на втором - все ОК.
в этом то и проблема,что у меня как у вас на втором скриншоте программа крэшится

Добавлено через 1 минуту
Цитата Сообщение от g_u_e_s_t Посмотреть сообщение
Я не к тому писал Внимательно прочитайте как работает realloc(). Подумайте что случиться если nextPos != str1
не могли бы вы подробнее написать,что случиться,я не очень понимаю
0
easybudda
Модератор
Эксперт CЭксперт С++
10208 / 6107 / 1536
Регистрация: 25.07.2009
Сообщений: 11,607
18.11.2012, 06:12 10
Rexer, как-то сложно у вас всё, я бы проще сделал
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
char * dyncat(const char * str1, const char * sep, const char * str2) {
    char * ret = malloc(strlen(str1) + strlen(sep) + strlen(str2) + 1);
    if ( ! ret )
        return NULL;
 
    sprintf(ret, "%s%s%s", str1, sep, str2);
 
    return ret;
}
 
int main(void) {
    char * str, * words[] = { "one", "two" };
 
    printf("%s\n", ( str = dyncat(words[0], " ", words[1]) ));
    free(str);
 
    return 0;
}
http://codepad.org/1R8PhE0d
1
g_u_e_s_t
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
18.11.2012, 10:31 11
Цитата Сообщение от Rexer Посмотреть сообщение
что случиться,я не очень понимаю
в main() останется первоначальное значение str1 - все умрет.
Вон Вам easybudda, вполне нормальный вариант показал, можете использовать или переписать под семантику типа
C
1
char *strmcat(const char *, ...);
будет сколько угодно строк за раз склеивать.
1
Rexer
165 / 164 / 46
Регистрация: 10.10.2010
Сообщений: 725
19.11.2012, 23:05  [ТС] 12
Я вас понял,что вы хотели сказать,но все же,я не понимаю в чем у меня ошибка,я понимаю ,что код написан кривовато,но что неверно то?
тем более я же специально присваиваю
C
1
str1 = nextPos;
Мне нужно понять где я ошибаюсь!
0
easybudda
Модератор
Эксперт CЭксперт С++
10208 / 6107 / 1536
Регистрация: 25.07.2009
Сообщений: 11,607
19.11.2012, 23:32 13
Цитата Сообщение от Rexer Посмотреть сообщение
я не понимаю в чем у меня ошибка
Цитата Сообщение от Rexer Посмотреть сообщение
void myStrcat(char* str1, char *str2)
Указатель на первую строку нужно по ссылке передавать, а не по значению. При таком, как у Вас подходе функция имеет свою собственную переменную-указатель, которой при вызове функции присваивается значение вашей str1. Внутри функции realloc (как Вам выше говорили) присваивает этой переменной какое-то новое значение, которое при выходе из функции благополучно теряется, а объявленная в main переменная str1 указывает на фактически свободную память, в которой всё ещё лежит изначальная строка. При втором вызове Вы функции передаёте указатель на память, которая уже не значится выделенной, вот программа и падает.
2
polyaKIDze
63 / 63 / 20
Регистрация: 16.07.2012
Сообщений: 147
20.11.2012, 01:06 14
easybudda, спасибо за объяснения. Я тоже из этого полезное для себя вынес.
А если оставить вариант Rexer'а, сделав, либо чтобы функция возвращала указатель, либо чтобы в функцию передавался указатель на указатель. Первое не нравится "непохожестью" на библиотечную функцию. Второе вы предложили вроде.
Поясните пожалуйста, возможно ли первое? И правильно ли я понял ваше предложение?
0
easybudda
Модератор
Эксперт CЭксперт С++
10208 / 6107 / 1536
Регистрация: 25.07.2009
Сообщений: 11,607
20.11.2012, 09:53 15
Цитата Сообщение от polyaKIDze Посмотреть сообщение
А если оставить вариант Rexer'а, сделав, либо чтобы функция возвращала указатель, либо чтобы в функцию передавался указатель на указатель. Первое не нравится "непохожестью" на библиотечную функцию. Второе вы предложили вроде.
Основная проблема в том, что функция может принимать указатель на один участок памяти, а возвращать на другой. Если заставить функцию возвращать указатель и просто присваивать его значение str1, прежнее значение str1 будет потеряно, то есть получите утечку памяти. Я в 10 посте не зря сделал, чтобы функция возвращала указатель на выделенный внутри неё участок памяти, который заведомо не связан с переданными в параметрах. Если так хочется прицеплять к существующей строке продолжение, можно нехитрую оболочку сделать:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
char * dyncat(const char * str1, const char * sep, const char * str2) {
    char * ret = malloc(strlen(str1) + strlen(sep) + strlen(str2) + 1);
    if ( ! ret )
        return NULL;
 
    sprintf(ret, "%s%s%s", str1, sep, str2);
 
    return ret;
}
 
char * mycat(char ** s1, const char * s2) {
    char * tmp = dyncat(*s1, "", s2); /* забыв, что разделитель можно задавать */
    if ( ! tmp )
        return NULL;
    free(*s1);
    *s1 = tmp;
 
    return *s1;
}
 
int main(void) {
    char * str;
 
    if ( ! ( str = malloc(4) ) ) {
        perror("malloc");
        exit(1);
    }
 
    strcpy(str, "one");
    printf("%s\n", mycat(&str, " two three"));
 
    free(str);
    exit(0);
}
http://codepad.org/RPuEzkbA
2
g_u_e_s_t
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
20.11.2012, 10:06 16
Простите, искать лень А на Винде есть что-нибудь похожее на [v]asprintf() ?
Касательно, ф-ции: дело вкуса конечно, но вот лично мне при работе со строками, дико не нравиться free() на память выделенную в другом месте.
1
easybudda
Модератор
Эксперт CЭксперт С++
10208 / 6107 / 1536
Регистрация: 25.07.2009
Сообщений: 11,607
20.11.2012, 10:43 17
Цитата Сообщение от g_u_e_s_t Посмотреть сообщение
дико не нравиться free() на память выделенную в другом месте
Ну тут ещё лёгкий случай - в main память выделили, в main и освободили. А внутри mycat значение указателя и вовсе может не измениться. Фактически handmade_realloc
А вот пользуясь функциями вроде strdup или той же asprintf действительно важно не забывать освобождать память, которую они выделяют. Но учитывая, насколько ими порой удобно пользоваться, можно, думаю, справиться с лёгкими приступами когнитивного диссонанса и смириться с тем, что память не только malloc/calloc/realloc выделяют
А в виндовой реализации gcc asprintf должна бы быть (проверить сейчас не на чем), strdup есть, на сколько помню...
1
g_u_e_s_t
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
20.11.2012, 10:50 18
Цитата Сообщение от easybudda Посмотреть сообщение
Ну тут ещё лёгкий случай - в main память выделили, в main и освободили
Я ж не конкретно, про Ваш пример, а подходе в целом.
Цитата Сообщение от easybudda Посмотреть сообщение
А в виндовой реализации gcc asprintf должна бы быть (проверить сейчас не на чем), strdup есть, на сколько помню...
strdup() в отличии от, хотя бы POSIX. А "нативная" asprintf() для виндоуз с ходу не нагуглилась, вот и спросил.
ЗЫ: как говорит один мой хороший знакомый "Ну какая может быть работа со строками в языке название которого состоит из одной буквы"
1
Rexer
165 / 164 / 46
Регистрация: 10.10.2010
Сообщений: 725
20.11.2012, 16:31  [ТС] 19
Цитата Сообщение от easybudda Посмотреть сообщение
Указатель на первую строку нужно по ссылке передавать, а не по значению. При таком, как у Вас подходе функция имеет свою собственную переменную-указатель, которой при вызове функции присваивается значение вашей str1. Внутри функции realloc (как Вам выше говорили) присваивает этой переменной какое-то новое значение, которое при выходе из функции благополучно теряется, а объявленная в main переменная str1 указывает на фактически свободную память, в которой всё ещё лежит изначальная строка. При втором вызове Вы функции передаёте указатель на память, которая уже не значится выделенной, вот программа и падает.
Если мы пишем в C, то как передать по ссылке?
В целом все остальное понял,спасибо вам большое!Вы мне очень помогли!
0
easybudda
Модератор
Эксперт CЭксперт С++
10208 / 6107 / 1536
Регистрация: 25.07.2009
Сообщений: 11,607
20.11.2012, 18:00 20
Цитата Сообщение от Rexer Посмотреть сообщение
Если мы пишем в C, то как передать по ссылке?
Да вот же:
Цитата Сообщение от easybudda Посмотреть сообщение
char * mycat(char ** s1, const char * s2)
Указатель на указатель на строку.
1
20.11.2012, 18:00
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
20.11.2012, 18:00

Динамическое выделение памяти
Пользователь вводит число. Программа динамически выделяет массив типа char...

Динамическое выделение памяти
Приветствую. Имеется код: #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; ...

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru