LINUX.ORG.RU

вопрос по C (массив указателей на указатели)


0

1

в общем есть вопрос. есть программа, в программе есть случайное количество char[] произвольной длины, количество от 10, до 1000. в общем вопрос.

как выделить память с помощью malloc(number_ofstrings * 4);

технически вроде все понятно и должно работать, адрес массива указателей будет возвращен вызовом malloc, от этого адреса будут отсчитываться элементы из рассчета 4байта на элемент, в каждый элемент буду класть адрес malloc(len_of_char_string)

вот только вопрос, как инициализировать массив указателей в памяти, выделенной функцией malloc.

надеюсь, понятно спрашиваю

Перемещено mono из admin

★★

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

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

Зачем?

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

IvanR ★★ ()
char** strings = (char**) malloc ( number_ofstrings * sizeof(char*) )

выделит память под number_ofstrings указателей. Память под сами строки, ясное дело, надо выделять отдельно. Обращаться к отдельному указателю можно как к элементу массива.

 printf ( "Third string: %s\n", strings[2] );
Или с помощью адресной арифметики:
 prinf ( "Second string %s\n", *(strings+1) );

Только почему это в Admin? =)

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

Ясно. Наверное я понял. Кажется.

Здесь нужно разделить пару моментов.
1) Ты выделишь память на массив указателей. Это НЕ на строки, а только на их указатели.
2) Выделяешь память на строки. Вот на этом шаге у тебя и будет инициализация указателей. Каждому указателю из массива нужно будет присвоить адрес строки, malloc.

P.S. Только не стоит привязывать указатель к 4-м байтам. Это будет непереносимо.

hibou ★★★★★ ()
char** strings = (char**) malloc ( number_ofstrings * sizeof(char*) );
for (int i=0; i < number_ofstrings; i++)
{
  strings[i] = malloc(string_len * sizeof(char));
}

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

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

Перечитал вопрос, совсем запутался. Если речь не об инициализации, а об обычном заполнении данными, то так:

 strings[2] = (char*) malloc ((new_string_length+1)*sizeof(char));

Или так:

 *(strings+2) = (char*) malloc ((new_string_length+1)*sizeof(char)); 
roof ★★ ()
Ответ на: комментарий от marvin_yorke

А зачем умножать на sizeof(char)? Он всегда равен 1

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

именно то, что я искал, только мне больше нравится вот так объявлять

char *point_arr[]

все-таки правильнее выглядит, на мой взгляд, но компилятору пофиг

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

в первом посте вы написали именно то, что мне нужно

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

А зачем умножать на sizeof(char)? Он всегда равен 1

В C++ да, а в C — нет. В C может быть равен 4, например.

i-rinat ★★★★★ ()

Сделайте списком и не парьтесь.

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

When applied to an operand that has type char , unsigned char , or signed char , (or a qualified version thereof) the result is 1.

Из ANSI C, 3.3.3.4 The sizeof operator.

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

В C++ да, а в C — нет. В C может быть равен 4, например.

Это ты про размер символа говоришь, например 'a'. char - это тип целочисленных данных, sizeof от которого всегда равен 1. И в С, и в С++.

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

А зачем умножать на sizeof(char)? Он всегда равен 1

считайте, что это правило хорошего тона, если аллоцируется вектор. для int умножить на sizeof(int), для wchar_t на его sizeof. То есть выделяя память под вектор показать не только кол-во элементов, но и имя_типа элемента каждого.

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

Если компилятор следует стандартам, то да. Если не следует - его проблемы.

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

А зачем умножать на sizeof(char)? Он всегда равен 1

Ога, а sizeof(char*) всегда равен 4.

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

Стандарты описывают минимальную границу. Например для архитектур, где минимальная длина адресации 16 бит (правда я из таких знаю только DCPU-16, но ситуация всё же теоретически возможна), char разработчику компилятора логично сделать 16-битным.

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

А кто здесь что-то говорит про количество бит? В чаре может быть 100500 бит, но sizeof от него всё равно будет равен 1

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

В чаре может быть 100500 бит, но sizeof от него всё равно будет равен 1

Хм… но всё равно стоит предостеречься, а то вдруг в каком-нибудь c31 будет 4-байтный char и 1-байтный byte. Да и код читабельнее.

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

где минимальная длина адресации 16 бит

Я тоже думал, что sizeof возвращает размер в байтах (8-битных), но sizeof возвращает размер в размерах char. Так что логично, что размер char'а в char'ах всегда 1.

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

но ситуация всё же теоретически возможна

Я для себя решил что не стоит закладываться на экзотические архитектуры. x86, mips и arm вполне достаточно, имхо. Я не верю что появятся новые процы с байтами не по 8 бит или ещё какой фигнёй. А если таки изобретут какие-нить троичные компы то код для них всё равно нужен будет новый, а старый будут пускать под эмуляцией/в режиме совместимости.

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

Но всё равно с точки зрения стиля имхо лучше писать malloc(count*sizeof(type)), даже если sizeof(type) заведомо 1.

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

Кстати, я надеюсь ТСу сказали что если к указателю прибавить 1, то компилер сам выщитает адрес следующего элемента в массиве (тред не читал)? Т.е. все эти махинации с +4 или +8 байт не только не нужны, но и вредны со всех сторон.

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

Тогда лучше calloc :)

А, ну я в С не умею и таких тонкостей не знаю (-:

PolarFox ★★★★★ ()

Сразу после malloc()...

... Делаем man memset, либо что иной раз лучше, man calloc.

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

Кстати, ...

... для массива проще было бы его размер получать через strlen. И, в принципе, пофиг что это не «строка». Как таковых «строк» в С нет.

anonymous ()
Ответ на: Кстати, ... от anonymous

Размер массива проще получать через sizeof, а за использование strlen для произвольного куска памяти, для которого не гарантируется наличие 0 в конце, надо сразу отрывать руки. По самые ноги.

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

Пардон, а кто сказал...

... что строка не завершена 0? И как часто такие строки встречаются, в особенности если учесть что постоянно приходится либо увеличивать, либо уменьшать длину на 1? Далее. А что есть «массив» как не произвольный кусок памяти? Судя по malloc, он и есть. ;)

Вообще говоря, sizeof это оператор для определения размерности типа данных. Так что, если ТС не вводил свой тип данных (сделать это можно, но вряд ли нужно), лучше бы пользоваться strlen. Ибо именно strlen возвращает длину «строки» (в данном случае число символов в «массиве»). Тут имеет смысл не пытаться выдернуть себе руки до ног, а обращать внимание на семантику (слово знакомое?) происходящего в коде. Для полного просветления в мозгу — читать info strlen. Там есть примеры, разберитесь, сделайте милость?

anonymous ()
Ответ на: Пардон, а кто сказал... от anonymous

А что есть «массив» как не произвольный кусок памяти?

K&R, глава 1.6 (в моём издании страница 36)

Вообще говоря, sizeof это оператор для определения размерности типа данных.

Правда?

int a[10];
int b = sizeof(a);
int c = sizeof("hello, world");
Чему равно b? А с?

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

вот только вопрос, как инициализировать массив указателей в памяти, выделенной функцией malloc.

руками.

for(int j = 0; j < N; j++)
    a[j][0] = '\0';

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

В C может быть равен 4, например.

K&R плачут горючими слезами ☹

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

Ога, а sizeof(char*) всегда равен 4.

нет. sizeof(xyz*) всегда равен размеру указателя в системе. Т.е. зависит от самой системы. в Slackware64 очевидно равен 64/8.

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

Дальше читай.

ну извини. От того, что ты понял, что это чушь, чушью это быть не перестало.

Толку-то от твоих K&R. Ты вообще видел код тех времён? Сейчас их диалект и современный называли бы разными языками.

видел я код. Нормально в нём всё. Может ты с java/php сравниваешь? А Pure C оно и сегодня такое же. Можешь ненавидеть и обс^Wкритиковать, но это ничего не меняет.

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

Можешь ненавидеть и обс^Wкритиковать, но это ничего не меняет

He who can, does; he who cannot, teaches.

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

He who can, does; he who cannot, teaches.

я-то тут при чём? код такой же самый, как и в K&R. А если его попытаться улучшить, получается PHP.

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

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

собственно вот так все выглядит:

    char **obj_pointers_arr = (char**)malloc((spaces + 2) * sizeof(int));//alloc memory to array of pointers
    for (i = 0; command_line[i] != '\n'; i++) {
        if (command_line[i] != ' ') {
            obj_len = str_len(&command_line[i], ' ');
            obj_pointers_arr[obj_counter] = malloc(obj_len + sizeof(char));//alloc mem to char string and init array
            objcpy(&command_line[i], obj_pointers_arr[obj_counter], ' '); //add '\0'
            i = i + (obj_len - 1);
            obj_counter++;
        }
    }

IvanR ★★ ()

4байта на элемент

Убью.

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

кажется понял:

sizeof(obj_pointers_arr[0])

а еще лучшенаверно так:

sizeof(char*)

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

чтобы освободить массив указателей нужно сделать free(strings)?

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

А вот мой пример...

...

#include <stdio.h>
#include <string.h>

void some_func(const char *some_str){
printf("Задали строку :%s, strlen = %d, sizeof = %d\n", some_str, strlen(some_str), sizeof(some_str));
}

int main(int argc, char *argv[]){
some_func(argv[1]);
return 0;
}

При ./a.out Test_string получаем strlen = 11, sizeof = 4. С каким вариантом проще было бы выполнить malloc?

Кстати, ТС, действительно и серьезно рекомендую использовать calloc. При выделении памяти она сразу будет проинициализирована нулем и ненужно будет еще memset делать. Так слегка удобнее — одна ф-я заместо двух. Меньше поводов накосячить.

anonymous ()
char **do_the_job(char **str, unsigned num_of_strings)
{
	char **a = (char **)malloc(num_of_strings*sizeof(char *));

	int i=0;
	while (i<num_of_strings) {
		a[i] = (char *)malloc(strlen(str[i]));
		++i;
	}
        return a;
}
nanoolinux ★★★★ ()
Ответ на: комментарий от IvanR
void undo_the_job(unsigned num_of_strings, char **a)
{
	int i=0;
	while (i<num_of_strings) {
		free(a[i]);
		++i;
	}
	free(a);
}
nanoolinux ★★★★ ()
Ответ на: комментарий от IvanR

Эммм...

... Я прошу прощения, но что-то (видимо, command_line) мне пытается намекнуть на то, что Вам стоило бы рассмотреть getopt/getopt_long. Возможно я и не прав.

Возможно Вам будет интересно — info "(standards)User Interfaces".

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

А вот тут я весь в свисток уйду...

... ))) Окромя free(a); желательно еще сделать a = NULL. Причина в том, что memory manager в рантайме после «просто free» не зануляет память. Отдельным... «индивидуумам» удается и читать оттуда и писать туда с весьма херовыми последствиями. Лучше принудительно сказать менеджеру памяти из glibc что все, нам данный кусок памяти более ни к чему, пусть система его использует по своему усмотрению. Мы им воспользоваться уже не сможем гарантированно.

anonymous ()
Ответ на: Эммм... от anonymous

я знаю, что такое getopt_long, в общем немного не то, тоесть то в принципе, но то, что я привел как раз предназначено чтобы вручную создать *argv[]

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