powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Массивы переменной длины. Инициализация.
16 сообщений из 16, страница 1 из 1
Массивы переменной длины. Инициализация.
    #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
Массивы переменной длины. Инициализация.
    #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
Массивы переменной длины. Инициализация.
    #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
Массивы переменной длины. Инициализация.
    #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
Массивы переменной длины. Инициализация.
    #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
Массивы переменной длины. Инициализация.
    #34808981
teras

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

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

Остальное вроде переделала.
...
Рейтинг: 0 / 0
Массивы переменной длины. Инициализация.
    #34809001
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
Массивы переменной длины. Инициализация.
    #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
Массивы переменной длины. Инициализация.
    #34809217
сдаюсь. Как передать массив так, чтобы можно было его заполнить ((?
...
Рейтинг: 0 / 0
Массивы переменной длины. Инициализация.
    #34809652
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
Массивы переменной длины. Инициализация.
    #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
Массивы переменной длины. Инициализация.
    #34812242
ErV
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Галина Зайцева wrote:

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

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

А оно есть в простом Си. Который не объектный? Я пока на простом Си учусь.
...
Рейтинг: 0 / 0
Массивы переменной длины. Инициализация.
    #34813001
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Галина ЗайцеваА оно есть в простом Си. Который не объектный? Я пока на простом Си учусь.Нет, нету. Зато в простом Си есть списки которые с легкостью решают задачу безразмерных массивов без лишних перераспределений памяти. Вам структуры уже давали?
...
Рейтинг: 0 / 0
Массивы переменной длины. Инициализация.
    #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
Массивы переменной длины. Инициализация.
    #34822401
В файле числа разделены пробелами как раз. )) Но это не проблема, чем они разделены. Остальные комменты и исправления принимаются. Но я еще дополнения сделала. Но о них попозже.
...
Рейтинг: 0 / 0
16 сообщений из 16, страница 1 из 1
Форумы / C++ [игнор отключен] [закрыт для гостей] / Массивы переменной длины. Инициализация.
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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