• Познакомьтесь с пентестом веб-приложений на практике в нашем новом бесплатном курсе

    «Анализ защищенности веб-приложений»

    🔥 Записаться бесплатно!

  • CTF с учебными материалами Codeby Games

    Обучение кибербезопасности в игровой форме. Более 200 заданий по Active Directory, OSINT, PWN, Веб, Стеганографии, Реверс-инжинирингу, Форензике и Криптографии. Школа CTF с бесплатными курсами по всем категориям.

Рваные массивы

  • Автор темы masime
  • Дата начала
M

masime

У меня в рваном массиве способ хранения кол-ва элементов - терминальный символ в конце строки. Записать я его записал, но как его мне прочитать? Помогите, пожалйста. Вот код:
[codebox]//Создание массива
double** ConstructAr()
{
double** p = NULL;
int N, M;
//poluchaem lo-vo strok
do
{
randomize();
N = random(10);
}while (N < 1 || N > 10);
printf("N = %d", N);
//videlyaem pamyat'
p = (double**)malloc( sizeof(double*)*N + sizeof(int));
//zapominaem v -1 kol-vo strok
((int*)p)[0] = N;
//sdvigaem ukasatel'
((int*)p)++;

//organizuem postrochnyi vvod
for (int i=0; i<N; i++)
{
//opredelyaem kol-vo simvolov v stroke
do
{
randomize();
M = random(10);
}while(M < 1 || M > 10);
printf("M = %d", M);
//videlyaem pamyat'
p = (double*)malloc((M+1)*sizeof(double) + sizeof(int));
((int*)(p))[M+1] = M;
//vvodim elti s klavy
for (int j=0; j<M; j++)
{
double m;
do
{
printf("\nEnter A[%d][%d](1<=A[%d][%d]<=10): ", i,j,i,j);
scanf("%lf", &m);
}while(m<1 || m>10);
p[j]=m;
}

}
return p;
}
//вывод массива на экран
void PrintArray(double **p)
{
int N,M;
N = ((int*)p)[-1];

for(int i=0; i<N; i++)
{
M = //вот здесь как его мне получить?
for(int j=0; j<M; j++)
printf("%-6.2lf", p[j]);
printf("\n");
}

}[/codebox]
 
S

shisik

Что-то я не совсем понял проблему. Если мне нужно сделать многомерный массив со строками разной длины, я пишу эту длину в начало массива. Кстати, именно так у тебя и сделано для N: ((int*)p)[0] = N; Другого варианта быть не может, т.к. найти неизвестную длину по адресу, который от этой длины как раз и зависит, невозможно.
И ещё. Здесь ты выделяешь лишний элемент:
p = (double*)malloc((M+1)*sizeof(double) + sizeof(int));
((int*)(p))[M+1] = M;

Если ты хочешь записать длину в конец, то зачем выделять M+1 ячеек для данных и ещё одну для длины? Ячейка со смещением M в таком случае будет пустой, т.е. достаточно выделить malloc(M*sizeof(double) + sizeof(int)); Кстати, в случае с N ты именно так и делаешь.
В таком случае на твой вопрос "M = //вот здесь как его мне получить?" можно ответить так:
Код:
M = ((int*)p)[i][0];
Кстати, если в ((int*)p)[0] ты записывашь длину массива, а потом сдвигаешь указатель ((int*)p)++;, то ты эту длину можно сказать теряешь :) Я б сказал, это плохой тон...
 
M

masime

Задачу придумал не я. И если есть такое условие, значит у нее есть и решение. Длину этого массива по условию необходимо хранить в конце.
Если ты хочешь записать длину в конец, то зачем выделять M+1 ячеек для данных и ещё одну для длины?
тут действительно косяк((. Но в задче у меня указано: способ хранения кол-ва элементов - терминальный символ в конце строки, а способ хранения количества строк - число в -1 эл-те вектора указателей.
 
S

shisik

Тогда всё ясно. нужно выделить какой-то один символ (число), как служебное. Обычно это 0 (в обычных строках char *) и его ставить на конце строки. Но у такого способа есть недостаток - другие элементы массива не могут быть нулями, иначе они будут неверно опознаны как конец строки и все следующие символы этой строки будут потеряны.
Вот как-то так:
Код:
#include <stdio.h>

const int TERM = -1;

int N;
int M;


int main()
{
N = rand() % 10;

double **p = (double **) malloc(N * sizeof(double*) + sizeof(int));

((int *)p)[0] = N;

double ps;
int i, j;
for (i = 1; i < N + 1; i++) {
M = rand() % 10;

p[i] = (double *) malloc(M * sizeof(double) + sizeof(int));
((int *)p + i)[M] = TERM;

for (j = 0; j < M; j++)
p[i][j] = (double) (rand() % 10);
}

for (i = 1; i < N + 1; i++) {
j = 0;
while (((int *)p + i)[j] != TERM)
printf("%f\n", p[i][j++]);
}

return 0;
}
 
G

Guest

Можно использовать не один символ.
Например, любую из esc-последовательностей
тогда проблема решится
 
S

shisik

Ну, не на 100%, но в значительной мере это выход. Просто если такой последовательностью будет, скажем, 12345, то теоретически она может встретиться и в середине массива, что приведёт к ошибочному определению его длины :) Хотя вероятность этого значительно ниже, чем с 1 символом...
 
G

Guest

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

masime

Подскажите пожалйста, что в этой программе не так и почему она не работает. Сделал как советуетshisik, но все равно не получается(

Код:
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>


//Prototype func
void PrintArray(double **p);
double** ConstructAr();
void DestructArray(double **p);

const int TERM = -1;

/////////////////////////////////

void main (void)
{
double **pA;
clrscr();

pA = ConstructAr();
PrintArray(pA);
DestructArray(pA);
getch();
}

double** ConstructAr()
{
double **p = NULL;
int N, M;
//poluchaem lo-vo strok
do
{
randomize();
N = random(10);
}while (N < 1 || N > 10);
printf("N = %d", N);
//videlyaem pamyat'
p = (double **)malloc(N*sizeof(double*) + sizeof(int));
//zapominaem v -1 kol-vo strok
((int *)p)[0] = N;

//organizuem postrochnyi vvod
for (int i=1; i<N+1; i++)
{
//opredelyaem kol-vo simvolov v stroke
do
{
randomize();
M = random(10);
}while(M < 1 || M > 10);

printf("M = %d", M);
//videlyaem pamyat'
p[i] = (double *) malloc(M*sizeof(double) + sizeof(int));
((int *)p+i)[M] = TERM;
//vvodim elti s klavy
for (int j=0; j<M; j++)
{
double m;
do
{
printf("\nEnter A[%d][%d](1<=A[%d][%d]<=10): ", i,j,i,j);
scanf("%lf", &m);
}while(m<1 || m>10);
p[i][j]=m;
}
}
return p;
}
void DestructArray(double **p)
{
if(!p) return;//proverka korrekt

int N; // kol-vo strok
N = ((int *)p)[-1];
for(int i=0; i<N; i++)
{
((int *)(p[i]))--;
free(p[i]);
}
((int *)p)--;
free(p);
printf("End free");
}

void PrintArray(double **p)
{
int N;
N = ((int*)p)[0];
printf("Poluch N=%d", N);
getch();

for(int i=1; i<N+1; i++)
{
getch();
int j = 0;
while(((int *)p+i)[j] != TERM)
printf("%f ", p[i][j++]);
printf("\n");
}
}
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!