Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Массивы переменной длины. Инициализация. / 16 сообщений из 16, страница 1 из 1
18.09.2007, 15:38:16
    #34808490
Массивы переменной длины. Инициализация.
я пока только начинаю, похтому появился вопрос: Как инициализировать матрицу со строками переменной длины?

Пример. Есть файл со строками целых чисел(максимум трехзначных). Надо создать массив, полное отражение файла.

Пока делаю примерно так:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
int main(void){
FILE *fd;
int ed_size = sizeof(int);
int *chisla[ 5 ];
int i, j, chis, 
char str_ch[ 4 ];

fd = fopen("proto_arr.dat", "r");
i= 0 ; j= 1 ;
while(fgets(fd,  120 , str_ch) != "\n"){
  while(sscanf(str_ch, "%8d", &chis) >  0 ){
     realloc(chisla[i], j*ed_size);
     chisla[i][j- 1 ] = chis;
     ++j;
  }
  ++i;
}

return  0 ;
}

Корректна ли такая реализация?
...
Рейтинг: 0 / 0
18.09.2007, 16:44:11
    #34808801
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Массивы переменной длины. Инициализация.
Галина Зайцева пишет:

> Корректна ли такая реализация?
Нет

realloc returns a void pointer to the reallocated (and possibly moved) memory
block.

If there is not enough available memory to expand the block to the given size,
the original block is left unchanged, and NULL is returned

т.е. должно быть что-то типа :
chisla = realloc(chisla, j*ed_size);

и потом еще и проверка ошибки выделения памяти.

> chisla[j-*1*] = chis;
> ++j;
> }
> ++i;
> }
>
> return *0*;
> }
>
>
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
18.09.2007, 17:06:23
    #34808920
teras
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Массивы переменной длины. Инициализация.
Еще пара комментариев.

Галина Зайцева пишет:
> int *chisla[5];
Массив размером 5 указателей, а по тексту не видно ограничения в пять строк - на шестой строке будет переполнение.
Кроме того, массив не инициализируется, значит realloc будет работать с мусором.

> char str_ch[4];
Размер строки - всего 3 символа

> fd = fopen("proto_arr.dat", "r");
Работет под win32? Добавте t в режит открытия- "rt"

> while(fgets(fd, 120, str_ch) != "\n"){
Тут вы сравниваете адреса, а не строки - напишите strcmp. Но не забедьте, что последняя строка может завершаться нулем, а по концу файла fgets возвращает NULL. Кроме того, в строку длиной три символа вы читаете 120 - явное переполнение.
Инициализировать элемент массива можно здесь (chisla = NULL)

> while(sscanf(str_ch, "%8d", &chis) > 0){
sscanf будет читать каждый раз с начала строки одно и тоже число - нужно увеличивать указатель, пропуская прочитанную область.
Дальше уже написано.
...
Рейтинг: 0 / 0
18.09.2007, 17:12:41
    #34808947
Массивы переменной длины. Инициализация.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
void parse_str(char *s, int *val){
	int k =  1 ; int l =  0 ;
	char promstr[ 4 ];
	int promchis;
	
	while(*s){
		while(*s != '\t')
			promstr[l++] = *s++;
		promchis = atoi(promstr);
		val = realloc(val, k*sizeof(int));
		if(val == NULL){                                                //проверка на нехватку памяти
			printf("Not enogth memory !!!");
			exit( 1 );
		}
		val[k- 1 ] = promchis;
		k++;
	}
}

что неправильно?
...
Рейтинг: 0 / 0
18.09.2007, 17:16:14
    #34808959
Массивы переменной длины. Инициализация.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
#define MAXLINE  256 

int main(void){
	FILE *fd;
	int *dyn_arr[ 5 ];
	char c_str[MAXLINE +  1 ];
	
	fd = fopen("arr_vorlage.dat", "rt");
	int i= 0 ;
	while (fgets(c_str,  256 , fd) != NULL){
		printf("%s\n", c_str);
		parse_str(c_str, dyn_arr[i]);
		printf("\n");
		printval(dyn_arr[i]);
		++i;
	}
		

	fclose(fd);
	return  0 ;
}
...
Рейтинг: 0 / 0
18.09.2007, 17:20:08
    #34808981
Массивы переменной длины. Инициализация.
teras

Галина Зайцева пишет:
> int *chisla[5];
Массив размером 5 указателей, а по тексту не видно ограничения в пять строк - на шестой строке будет переполнение.
Кроме того, массив не инициализируется, значит realloc будет работать с мусором.

как его инициализировать? Думаю именно поэтому и не работает.

Остальное вроде переделала.
...
Рейтинг: 0 / 0
18.09.2007, 17:25:41
    #34809001
ErV
ErV
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Массивы переменной длины. Инициализация.
Галина Зайцева wrote:

> while (fgets(c_str, 256, fd) != NULL){
> printf("%s\n", c_str);
при считывании строки через fgets, будет считан также символ переноса
строки, т.е. "\n". У вас будут пустые строки между строчками.

Далее, что делает вот это?
> parse_str(c_str, dyn_arr );
как я понимаю, работать оно не будет, что бы там не было.
dyn_arr содержит указатель, который указывает "в никуда", и вы этот
указатель передаете в функцию как аргумент. В результате, вот тут:
> printval(dyn_arr);
на экран будет выведен мусор, и есть хороший шанс, что произойдет
accessviolation.
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
18.09.2007, 17:54:57
    #34809148
Массивы переменной длины. Инициализация.
ErV
Галина Зайцева wrote:

> while (fgets(c_str, 256, fd) != NULL){
> printf("%s\n", c_str);
при считывании строки через fgets, будет считан также символ переноса
строки, т.е. "\n". У вас будут пустые строки между строчками.

я дописала, чтобы последний символ менялся на '\0'.


Если под инициализацией понималось, присвоение начальных нулей, то я это сделала. Спасибо.
ErVДалее, что делает вот это?
> parse_str(c_str, dyn_arr );
как я понимаю, работать оно не будет, что бы там не было.
dyn_arr содержит указатель, который указывает "в никуда", и вы этот
указатель передаете в функцию как аргумент. В результате, вот тут:
> printval(dyn_arr);
на экран будет выведен мусор, и есть хороший шанс, что произойдет
accessviolation.
Posted via ActualForum NNTP Server 1.4


теперь все выглядет так:
Код: plaintext
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.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXLINE  256 

int parse_str(char *s, int *val){
	int k =  1 ; int l =  0 ;
	int promchis;
	
	while(*s != '\0'){
		char promstr[ 4 ];
		if (*s != '\0') return k;
		while(*s != '\t' || *s != '\0')
			promstr[l++] = *s++;
		promchis = atoi(promstr);
		if (val !=NULL ) val = realloc(val, k*sizeof(int));
		else val = (int*)malloc(sizeof(int));
		if(val == NULL){
			printf("Not enogth memory !!!");
			exit( 1 );
		}
		val[k- 1 ] = promchis;
		k++;
		*s++;
		l =  0 ;
	}
	return k;
}

void printval(int *val, int count){
	int i= 0 ;
	while(i < count){
		printf("%d", val[i]);
		i++;
	}
}

int main(void){
	FILE *fd;
	int *dyn_arr[ 5 ];
	char c_str[MAXLINE +  1 ];
	int i, count;
	 
        for(i= 0 ; i< 5 ; i++)
		 dyn_arr[i] = NULL;            //надеюсь это и есть инициализация?
	 
	fd = fopen("arr_vorlage.dat", "rt");
	i= 0 ;
	while (fgets(c_str,  256 , fd) != NULL){
		c_str[strlen(c_str)- 1 ] = '\0';
		printf("%s\n", c_str);
		count = parse_str(c_str, dyn_arr[i]);
		printf("\n");
		printval(dyn_arr[i], count);
		++i;
	}
		

	fclose(fd);
	return  0 ;
}
...
Рейтинг: 0 / 0
18.09.2007, 18:09:58
    #34809217
Массивы переменной длины. Инициализация.
сдаюсь. Как передать массив так, чтобы можно было его заполнить ((?
...
Рейтинг: 0 / 0
18.09.2007, 22:07:27
    #34809652
ErV
ErV
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Массивы переменной длины. Инициализация.
Галина Зайцева wrote:

> char promstr[4];
Это массив из 4х символов. Если хотите 4 строки, то надо char*
promstr[4];

>сдаюсь. Как передать массив так, чтобы можно было его заполнить ((?
char**

т.е., например:
Код: plaintext
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.
#include <string.h>
#define NUM_STRINGS

char* strCopy(const char* src){
        int len = (src) ? strlen(src):  0 ;
        char* result = new char[len+ 1 ];
        if (src)
                strncpy(result, src, len);
        result[len] =  0 ;
        return result;
}

void initStrings(char** args, int num){
        for (int i =  0 ; i < num ; i++)
                args[i] = strCopy("фыва");
}

void killStrings(char** args, int num){
        for (int i =  0 ; i < num; i++)
                delete[] args[i];
}

int main(int argc, char** argv){
        char* strings[NUM_STRINGS];
        initStrings(strings, NUM_STRINGS);
        for (int i =  0 ; i < NUM_STRINGS; i++)
                printf("%s\n", strings[i]);
        killStrings(strings, NUM_STRINGS);
}

не компилил, но должно работать.

Вообще, если вам надо динамические массивы и т.д., попробуйте
воспользоваться stl контейнерами типа vector, list и т.д.
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
19.09.2007, 11:20:46
    #34810439
Массивы переменной длины. Инициализация.
ErV

> char promstr[4];
Это массив из 4х символов. Если хотите 4 строки, то надо char*
promstr[4];

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

Теперь код выглядет примерно так:
Код: plaintext
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.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXLINE  256 
#define MAXVALS  100 

int *dyn_arr[ 5 ];

int parse_str(char *s, int *val){
	int k =  1 ; int l =  0 ;
	int promchis;
	
	while(*s != '\0'){
		char promstr[ 4 ];
		if (*s == '\0') return k- 1 ;
		while(*s != '\t' && *s != '\0')
			promstr[l++] = *s++;
		promchis = atoi(promstr);
/*		if (val !=NULL ) val = realloc(val, k*sizeof(int));
		else val = (int*)malloc(sizeof(int));*/
		if(val == NULL){
			printf("Not enogth memory !!!");
			exit( 1 );
		}
		val[k- 1 ] = promchis;
		k++;
		*s++;
		l =  0 ;
	}
	return k- 1 ;
}

void printval(int *val, int count){
	int i= 0 ;
	while(i < count){
		printf("%d\t", val[i]);
		i++;
	}
}

int main(void){
	FILE *fd;
	char c_str[MAXLINE +  1 ];
	int i, count;
	 for(i= 0 ; i< 5 ; i++){
		 dyn_arr[i] = (int*)malloc(MAXVALS*sizeof(int));
	 }
	fd = fopen("arr_vorlage.dat", "rt");
	i= 0 ;
	while (fgets(c_str,  256 , fd) != NULL){
		c_str[strlen(c_str)- 1 ] = '\0';
		printf("Эта строка прочитана из файла:\n%s\n", c_str);
		count = parse_str(c_str, dyn_arr[i]);
		printf("Эта строка массива после парсера:\n");
		printval(dyn_arr[i], count);
		printf("\n\n");
		++i;
	}

	fclose(fd);
	return  0 ;
}

но все же это не то, чего бы хотелось. Так как память выделяется заранее. А использованность сохраняется в параметре count. А если все же надо будет читать больше, чем выделено?
...
Рейтинг: 0 / 0
19.09.2007, 17:38:02
    #34812242
ErV
ErV
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Массивы переменной длины. Инициализация.
Галина Зайцева wrote:

> А если все же надо будет читать больше, чем выделено?
>
Возьмите stl контейнеры!
push_back и push_front в комбинации с std::string (или что вам там надо)
решат эти проблемы.
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
19.09.2007, 23:25:57
    #34812886
Массивы переменной длины. Инициализация.
ErV
Галина Зайцева wrote:

> А если все же надо будет читать больше, чем выделено?
>
Возьмите stl контейнеры!
push_back и push_front в комбинации с std::string (или что вам там надо)
решат эти проблемы.

А оно есть в простом Си. Который не объектный? Я пока на простом Си учусь.
...
Рейтинг: 0 / 0
20.09.2007, 02:04:49
    #34813001
White Owl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Массивы переменной длины. Инициализация.
Галина ЗайцеваА оно есть в простом Си. Который не объектный? Я пока на простом Си учусь.Нет, нету. Зато в простом Си есть списки которые с легкостью решают задачу безразмерных массивов без лишних перераспределений памяти. Вам структуры уже давали?
...
Рейтинг: 0 / 0
20.09.2007, 03:42:50
    #34813017
__Rosty__
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Массивы переменной длины. Инициализация.
Галина Зайцева
но все же это не то, чего бы хотелось. Так как память выделяется заранее. А использованность сохраняется в параметре count. А если все же надо будет читать больше, чем выделено?
Или два прохода (при первом проходе подсчитывается количество строк чисел),
или первым числом в файле proto_arr.dat должно быть записано количество строк в файле.

Смотрел прогу. В ней есть пару ошибок.
Напр. символ перевода строки: '\n'. '\t' - это табуляция.
Потом выделенную память хотя бы при выходе из программы желательно освободить.
Вместо int *dyn_arr; нужно int **dyn_arr;
И в процедуре parse_str после перекопирования цифр числа в promstr, нужно
было бы дописать нулевой символ.

Но не можно не признать, что для начала совсем не плохо. :)

P.S. Если я правильно понял, то в arr_vorlage.dat числа отделяются друг от
друга ОДНИМ пробелом и строка начинается с цифры или знака минус. Напр.

-123 78 889 675
67 -1 888
5 77 999 412 -7

Код: plaintext
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.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
#include "stdafx.h"


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

#define MAXLINE  256 

int **dyn_arr;   // массив чисел
int *counts;    // количество чисел в каждой строке
int row_counts;  // количество строк в файле

int parse_str(char *s, int **val, int ndx){
  int k =  0 ; 
  
  // Подсчет количесва чисел в строке
  char *str = s;
  while(*str != '\0'){
    while(*str >  32 )str++;
    k++;
    if(*str == ' ')str++;
  }
  
  // Выделение памяти
  val[ndx] = (int*)malloc(sizeof(int)*k);

  // Обработка чисел;
  str = s;
  int *ip = val[ndx];
  while(*s != NULL)
  {
    str = s;
    while(*str > ' ')str++;
    if(*str != '\0')
    {
      *str = '\0';
      str++;
    }
    *ip++ = atoi(s);
    s = str;
  }

  return k;
}

void printval(int *val, int count){
  for(int i= 0 ; i < count; i++)
    printf("%d\t", val[i]);
}

int main(void){
  FILE *fd;
  char c_str[MAXLINE +  1 ];
  int i, n, count;

  if((fd = fopen("arr_vorlage.dat", "rt")) == NULL)
  {
     printf( "Osibka pri otkritii arr_vorlage.dat \n" );
     exit( 1 );
  }

  // Сперва подсчет количества строк
  row_counts =  0 ;
  while (fgets(c_str,  256 , fd) != NULL)
    row_counts++;

  // Выделяем память
  dyn_arr = (int**)malloc(sizeof(int)*row_counts);
  counts  = (int*)malloc(sizeof(int)*row_counts);

  fseek(fd, 0L, SEEK_SET);  // Переход на начало файла

  // Считывание чисел
  i =  0 ; // Номер текущей строки
  while (fgets(c_str, MAXLINE, fd) != NULL)
  {
    // Обработка символа новой строки, ЕСЛИ имеется
    n = strlen(c_str) -  1 ;
    if(c_str[n] == '\n')
      c_str[n] = '\0';

    printf("Эта строка прочитана из файла:\n%s\n", c_str);
    count = parse_str(c_str, dyn_arr, i);
    counts[i] = count;  // Количество чисел в текущей строке

    printf("Эта строка массива после парсера:\n");
    printval(dyn_arr[i], count);
    printf("\n\n");
    ++i;
  }

  fclose(fd);
  
  // Освобождение выделенной памяти
  for(i= 0 ; i<row_counts; i++)
  {
    free(dyn_arr[i]);
  }
  free(dyn_arr);
  free(counts);

  printf("\nNazsmite ljubuju klavisu...\n");
  getch();
  return  0 ;
}
...
Рейтинг: 0 / 0
24.09.2007, 17:59:21
    #34822401
Массивы переменной длины. Инициализация.
В файле числа разделены пробелами как раз. )) Но это не проблема, чем они разделены. Остальные комменты и исправления принимаются. Но я еще дополнения сделала. Но о них попозже.
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Массивы переменной длины. Инициализация. / 16 сообщений из 16, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]