LINUX.ORG.RU

Ответ на: комментарий от comp00

Чтобы быстрее понять указатели, не нужны никакие Шилдты, а тем более Страуструпы, которые еще больше запутают человека. Как вариант мне в свое время помогло осиливания того же x86 ассемблера, после чего сразу все стало понятно и больше вопросов не возникало.

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

Почитал K&R, кое-что из «Глава 5. Указатели и массивы». Понял мало, но по своей проблеме узнал, что для того, чтобы передавать двумерный массив в функцию без указания размерности нужно передавать указатель на указатель. Завтра буду курить.

puding
() автор топика

Еще один платиновый тред. Одни неучи пытаются рассказать другим неучам то, чего сами не знают. dev во всём великолепии.

Чтобы быстрее понять указатели, не нужны никакие Шилдты, а тем более Страуструпы, которые еще больше запутают человека. Как вариант мне в свое время помогло осиливания того же x86 ассемблера, после чего сразу все стало понятно и больше вопросов не возникало.

Как же хорошо, что я знакомство с компьютером именно с ассемблера и начинал. (А если точнее, со схемотехники ЭВМ и принципов работы процессора.)

Все, кто пытается программировать, не зная, во что реально превращаются все объектно-ориентированные быдлокоды — поетнциальные обезьяны с гранатами. Никогда не знаешь, в какой момент вылезет их невежество и во что оно выльется.

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

Если ты говоришь о косвенности как о двойном (в общем случае - n-кратном) разыменовании указателя на указатель ([на указатель]*), то о какой косвенности может идти речь в случае

int arr[3][3] = {{1, 2, 3},
                 {4, 5, 6},
                 {7, 8, 9}};

, о котором говорю я?

Очевидно оно разворачивается в что-то типа

movl	$1, -48(%rbp)
movl	$2, -44(%rbp)
movl	$3, -40(%rbp)
movl	$4, -36(%rbp)
movl	$5, -32(%rbp)
movl	$6, -28(%rbp)
movl	$7, -24(%rbp)
movl	$8, -20(%rbp)
movl	$9, -16(%rbp)

т.о. доступ к элементу осуществляется именно по формуле из примера.

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

в случае

int arr[3][3] = {{1, 2, 3},
{4, 5, 6},
{7, 8, 9}};

о котором говорю я?

А, ты уже об этом случае говоришь... а ведь совсем недавно было:

yoghurt> Разве доступ к элементу i,j в Т*[] не работает как *(base + i*rows + j)

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

Между T[] и T[CONST] есть существенная разница.

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

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

Ну смысл в том, что многомерные массивы, хранятся не в виде абстрактного тела (таблица/куб etc) как удобно изображать человеку, а в виде указателей на указатели.

Двумерный массів: int[10][20] - честный сплошной участок памяті

То что вы описали - это массив одномерных массивов.

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

На этой неделе вообще по плюсам столько вопросов от тех, кто не читал k&r. Как будто k&r - многотомное собрание сочинений кернигана и риччи в 1200 страниц каждое, и всего 24 тома!!!

//фикседъ

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

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

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

typedef int MYCLASS;

#define WIDTH  3
#define HEIGHT 2 

MYCLASS a[WIDTH][HEIGHT];

typedef MYCLASS A[WIDTH][HEIGHT];


void print(A*a , int x,int y)
{

 for(int i=0;i<x;i++)
 for(int j=0;j<y;j++)
 { 
  printf("[%d][%d]=%d\n",i,j,(*a)[i][j]);
 }

}

int main(void)
{

 for(int i=0;i<WIDTH;i++)
 for(int j=0;j<HEIGHT;j++)
 { 
  a[i][j]=100*i+j;
 }

 A * a2=(A*)new int(WIDTH*HEIGHT);
 
 for(int i=0;i<WIDTH;i++)
 for(int j=0;j<HEIGHT;j++)
 { 
  (*a2)[i][j]=100*i+j;
 }
 print(&a,WIDTH,HEIGHT);
 printf("\n");
 print(a2,WIDTH,HEIGHT);
 return 0;
}

ilovewindows ★★★★★
()

Фух, разобрался.


//Задать размерность

int QwMatrixHeight = 20;
int QwMatrixWidth = 20;

//Создать матрицу

QwMatrixElement*** QwMatrix;


//Выделить память под элементы матрицы

for (int i = 0; i < QwMatrixHeight; i++) {

        for (int j = 0; j < QwMatrixWidth; j++) {

            QwMatrix[i][j] = new QwMatrixElement();

        }

    }


//Передача матрицы в функцию

void QwDoSomethingWithMatrix(QwMatrixElement*** matrix, int rows, int cols) {

    for (int i = 0; i < rows; i++) {

        for (int j = 0; j < cols; j++) {

            matrix[i][j]->someProperty = true;

        }

    }

}


//Использование в программе

QwDoSomethingWithMatrix(QwMatrix, QwMatrixHeight, QwMatrixWidth);

puding
() автор топика
Ответ на: комментарий от tailgunner

Это, как правильно сказали выше, массив массивов, а не многомерный массив.

В его коде еще и выделение памяти под массивы отсутствует.

anonymous
()
Ответ на: комментарий от puding
template <typename T>
void QwDoSomethingWithMatrix(T *matrix, int rows, int cols) {

    for (int i = 0; i < rows-1; i++) {

        for (int j = 0; j < cols-1; j++) {

            matrix[i][j]->someProperty = true;

        }
    }
}
nanoolinux ★★★★
()
Последнее исправление: nanoolinux (всего исправлений: 1)
Ответ на: комментарий от puding
#include <array>
#include <cstdio>

template <typename T, size_t h, size_t w>
using Matrix = std::array<std::array<T, w>, h>;

struct Something {
    bool property;
    int value;
    Something() : property(true) {}
};

template <size_t h, size_t w>
void doSomething(Matrix<Something, h, w>& mx)
{
    int x = 0;
    for (auto& col : mx)
        for (auto& el : col) {
            printf("%p\n", &el);
            el.value = ++x;
        }
}

int main()
{
    printf("sizeof cell = %ld\n", sizeof(Something));

    constexpr size_t h = 3, w = 3;

    Matrix<Something, h, w> mx;
    // movb	$1, (%rsp)
    // movb	$1, 8(%rsp)
    // movb	$1, 16(%rsp)
    // movb	$1, 24(%rsp)
    // movb	$1, 32(%rsp)
    // movb	$1, 40(%rsp)
    // movb	$1, 48(%rsp)
    // movb	$1, 56(%rsp)
    // movb	$1, 64(%rsp)

    doSomething(mx);

    for (size_t i = 0; i < h; ++i) {
        printf("{ ");
        for (size_t j = 0; j < w; ++j)
            printf("(%p){%d %d} ", &mx[i][j], mx[i][j].property, mx[i][j].value);
        puts("}");
    }
}

/*

sizeof cell = 8
0x7ff0000d8
0x7ff0000e0
0x7ff0000e8
0x7ff0000f0
0x7ff0000f8
0x7ff000100
0x7ff000108
0x7ff000110
0x7ff000118
{ (0x7ff0000d8){1 1} (0x7ff0000e0){1 2} (0x7ff0000e8){1 3} }
{ (0x7ff0000f0){1 4} (0x7ff0000f8){1 5} (0x7ff000100){1 6} }
{ (0x7ff000108){1 7} (0x7ff000110){1 8} (0x7ff000118){1 9} }

 */

/*

  total heap usage: 0 allocs, 0 frees, 0 bytes allocated

 */

Обрати внимание на 0 аллокаций в куче, на код аллокации на стеке, на дефолтный конструктор, на два способа обхода и на непрерывный layout элементов матрицы в памяти.

Если h и w неизвестны на момент компиляции, то нужно делать как предложил tailgunner, то есть писать свой класс с аллокацией одним куском и доступом с помощью арифметики i * w + j индексов. На самом деле (по стандарту), для статических T[h][w] и std::array<std::array<T, w>, h> компилятор сам располагает их непрерывно в памяти и пишет ту же самую арифметику для индексов в ассемблер для [ i ][j].

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

std::vector< std::vector< T> >

std::vector<std::vector<int>> xs = {{1, 2, 3}, {1, 2}, {1}, {}};

for (auto const& col : xs) {
    for (auto const& el : col)
        printf("(%p)%d ", &el, el);
    puts("");
}

/*
(0x59f91d0)1 (0x59f91d4)2 (0x59f91d8)3 
(0x59f9220)1 (0x59f9224)2 
(0x59f9270)1 

*/

/*
  total heap usage: 7 allocs, 7 frees, 144 bytes allocated
 */

144/4 = 36, куда ему столько? :)

int xs[][3] = {{1, 2, 3}, {1, 2}, {1}, {}};

for (auto const& col : xs) {
    for (auto const& el : col)
        printf("(%p)%d ", &el, el);
    puts("");
}

/*
(0x7ff0000e0)1 (0x7ff0000e4)2 (0x7ff0000e8)3 
(0x7ff0000ec)1 (0x7ff0000f0)2 (0x7ff0000f4)0 
(0x7ff0000f8)1 (0x7ff0000fc)0 (0x7ff000100)0 
(0x7ff000104)0 (0x7ff000108)0 (0x7ff00010c)0 
 */

/*
  total heap usage: 0 allocs, 0 frees, 0 bytes allocated
 */

(0x7ff00010c + 4 - 0x7ff0000e0) / 4 = 12 = 4 * 3.

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

это может приводить к code bloating если юзаются много інстансов с разнымі размерностями

Если много разных h и w, то тоже — класс с size_t (const если нет resize -> realloc) h, w; T *data; и i * w + j в operator().

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

А если размерности нормальные взять? 500х500?

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

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

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

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

чего то вывыливается в SIGSEGV

Упрямый ты. Ну как хочешь : ССЗБ. Подсказываю последний раз: man new, delete

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

рекомендую проверить. Сейчас под рукой GCC нет. Можно создать массив 2 на 2 и итерацией + печатью значений указателей на элементы проверіть.

anonymous
()
Ответ на: комментарий от anonymous
  1 #include<iostream>
  2 #define SIZE 4 
  3 int main(int argc, char **argv){
  4     int **array = new int*[SIZE];
  5     for(int i=0;i<SIZE;++i){
  6         array[i]=new int[SIZE];
  7     }
  8 
  9     for(int i=0; i<SIZE;++i){
 10         for(int j=0;j<SIZE;++j){
 11             std::cout<<" "<<&array[i][j];
 12         }
 13         std::cout<<"\n";
 14     }
 15     for(int i=0;i<SIZE;++i){
 16         delete array[i];
 17     }
 18     delete [] array;
 19     return 0;
 20 }

Результaт:

./tst 
 0x1989040 0x1989044 0x1989048 0x198904c
 0x1989060 0x1989064 0x1989068 0x198906c
 0x1989080 0x1989084 0x1989088 0x198908c
 0x19890a0 0x19890a4 0x19890a8 0x19890ac

Все правильно.

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

Я поясню: понятно, что память под вектор выделяются последовательно. Но совершенно не факт, что вектор буде идти один за другим.

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

Многомерный массів: int array[2][2] = {{0, 1}, {2, 3}};

Это (у меня) многомерный массив. А ты путаешь кучу со стеком

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

тупняк.
Массивы могут выделяться на стеке или на куче
естественно, что это совершенно разные структуры, и способы организации памяти у них разные.
Тот факт что в википедии под array подразумевают выделение на стеке, не означает что массивы, выделенные на куче не являются массивами.
Да по факту это не многомерный массив, в массив указателей. Но знаешь ли, компьютер тоже не с 0 и 1 работает, как в школе преподают.

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

однако понимание что ключ-значение бд есть включающая в себя указатели общность облегчает понимание указателей и вообще различение/общее среди имя-именуемое

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

А если размерности нормальные взять?

А 3x3 или 4x4 это не нормальные?

500х500?

Чтобы стек сорвать это мало, наверно. Нужно побольше.

#include <cstdio>
#include <vector>

template <typename T>
class Matrix {

    T *data;

public:

    typedef T data_type;

    const size_t rows, cols;

    Matrix(const size_t rows, const size_t cols) :
        data(new T[rows * cols]), rows(rows), cols(cols) {}

    ~Matrix() { delete[] data; }

    T& operator()(const size_t i, const size_t j) const {
        return data[i * cols + j];
    }

};

int main()
{

#ifdef VECTOR

    std::vector<std::vector<int> > mx(ROWS);
    for (size_t i = 0; i < mx.size(); ++i) {
        mx[i].resize(COLS);
        for (size_t j = 0; j < mx[i].size(); ++j)
            mx[i][j] = i * j;
    }

    long long sum = 0;
    for (size_t i = 0; i < mx.size(); ++i)
        for (size_t j = 0; j < mx[i].size(); ++j)
            sum += mx[i][j];

    printf("%lld\n", sum);

#else

    Matrix<int> mx(ROWS, COLS);

    for (size_t i = 0; i < mx.rows; ++i)
        for (size_t j = 0; j < mx.cols; ++j)
            mx(i, j) = i * j;

    long long sum = 0;
    for (size_t i = 0; i < mx.rows; ++i)
        for (size_t j = 0; j < mx.cols; ++j)
            sum += mx(i, j);

    printf("%lld\n", sum);

#endif

}
$ ~ g++ -DVECTOR -DROWS=15000 -DCOLS=20000 -O1 mx.cc
$ ~ \time ./a.out
22497375075000000
1.01user 0.60system 0:01.69elapsed 95%CPU (0avgtext+0avgdata 4692848maxresident)k
0inputs+0outputs (0major+293433minor)pagefaults 0swaps
$ ~ g++ -DROWS=15000 -DCOLS=20000 -O1 mx.cc
$ ~ \time ./a.out
22497375075000000
0.59user 0.85system 0:01.48elapsed 97%CPU (0avgtext+0avgdata 4691488maxresident)k
128inputs+0outputs (1major+3035minor)pagefaults 0swaps
$ ~ g++ -DVECTOR -DROWS=15000 -DCOLS=20000 -O2 mx.cc
$ ~ \time ./a.out
22497375075000000
0.75user 0.56system 0:01.38elapsed 94%CPU (0avgtext+0avgdata 4692864maxresident)k
0inputs+0outputs (0major+293435minor)pagefaults 0swaps
$ ~ g++ -DROWS=15000 -DCOLS=20000 -O2 mx.cc
$ ~ \time ./a.out
22497375075000000
0.44user 0.33system 0:00.79elapsed 97%CPU (0avgtext+0avgdata 4690672maxresident)k
0inputs+0outputs (0major+1503minor)pagefaults 0swaps
$ ~ g++ -DVECTOR -DROWS=15000 -DCOLS=20000 -Ofast mx.cc
$ ~ \time ./a.out
22497375075000000
0.47user 0.60system 0:01.15elapsed 93%CPU (0avgtext+0avgdata 4692864maxresident)k
0inputs+0outputs (0major+293435minor)pagefaults 0swaps
$ ~ g++ -DROWS=15000 -DCOLS=20000 -Ofast mx.cc
$ ~ \time ./a.out
22497375075000000
0.40user 0.34system 0:00.76elapsed 98%CPU (0avgtext+0avgdata 4691456maxresident)k
0inputs+0outputs (0major+992minor)pagefaults 0swaps

в случае vector<vector (ROWS + 1) аллокаций и локальность хуже, у второго варианта одна аллокация и, соответственно, всё одним куском.

quasimoto ★★★★
()

тут на лоре уже было

#include <stdlib.h>
#include <stdio.h>
int g=0;
void* m_init(size_t t){
	int* a=(int*)malloc(t*sizeof(int));
	int i;
	for(i=0;i<t;i++){
	  a[i]=g++;
	}
	return a;
}
void * g_dynarr(char* sz){
	if(!sz[1]){
		 return m_init(sz[0]);//simple test

	}
	void**p=malloc(sz[0]*sizeof(void*));
	int i;for(i=0;i<sz[0];i++){
		p[i]=g_dynarr(sz+1);
	}
	return p;
}
void cl(void* a,char* sz){
	return ;
}
int main(int c,char **z){
	char sz[]={10,10,0,1,1,10,0};//if short need +2 but ++;

	int i,j,k,l,m,n;
	//int***** a=(int*****)g_dynarr(sz);//bad_idia for g_dynarr(NULL) and g_dynarr("")
	/* sz={1,2,3,4,5,10,0};
	   for(i=0;i<sz[0];i++){
		for(j=0;j<sz[1];j++){
			for(k=0;k<sz[2];k++){
				for(l=0;l<sz[3];k++){
					for(m=0;m<sz[4];m++){
						for(n=0;n<sz[5];n++){
							printf(" %d",a[i][j][k][l][m]);
						}
						printf("\n");
					}
				}
			}
		}
	}*/
	
	{//test 10x10
		int **a=(int**)g_dynarr(sz);
		for(i=0;i<sz[0];i++){
			for(j=0;j<sz[1];j++){
				printf(" %d",a[i][j]);
			}
			printf("\n");
		}
		cl(a,sz);
	}
	{//test 2x3x4;
		sz[0]=2;sz[1]=3;sz[2]=4;g=0;
		//sz[2]=10;
		sz[3]=0;
		int ***a=(int***)g_dynarr(sz);
		for(i=0;i<sz[0];i++){
			printf("plane %d\n",i);
			for(j=0;j<sz[1];j++){
				for(k=0;k<sz[2];k++){
					printf(" %d",a[i][j][k]);
				}
				printf("\n");
			}
		}
		cl(a,sz);
	}
	return 0;
	
}

на стек оверфлоу где то было - да и вообще отличная стратегия - берём большой кусок M - принимаем за ноль его начало и тогда развлекаемся номер есть смещение в этом массиве и конструкция M[M[....]]

qulinxao ★★☆
()

не благодари. 0[a+i][a+j]

#include <stdio.h>
#define N 3
#define M 5
#define sz (N+1)*(M+1)
int a[sz];
int main(){
	int i,j;
	for(i=0;i<sz;i++)a[i]=(i/(N+1))*1000+i%(N+1);

	for(i=0,j=0;i<=N;i++,j+=(M+1))a[i]=j;

	for(i=1;i<=N;i++){
		for(j=0;j<M+1;j++)
			printf("%d ",0[a+i][a+j]);
		printf("\n");
	}

	printf("sizeof int %d byte",sizeof(int));
	return 0;
}
qulinxao ★★☆
()

для лучшего понимания 0[M+row][M+column][M+z ;)]

#include <stdio.h>
#define N 2
#define M 7
#define sz (N+1)*(M)
int a[sz];
int main(){
	int i,j,t;
	for(i=0;i<sz;i++){
		t=(i/(M));
		a[i]=t*100+(i%(M));
	}
	for(i=0,j=0;i<=N;i++,j+=(M))a[i]=j;

	for(i=0;i<sz;printf("%d ",a[i++]));printf("\n");

	

	for(i=0;i<=N;i++){
		for(j=0;j<M;j++)
			printf("%d ",0[a+i][a+j]);
		printf("\n");
	}

	printf("sizeof int %d byte",sizeof(int));
	return 0;
}
qulinxao ★★☆
()

Почти дописал, вываливается в SIGSEGV в main при доступе к элементу матрицы, хотя в функции выполняется

#include <iostream>

using namespace std;

//Элемент матрицы

class someType {

private:

    bool state;

public:

    void setState(bool value) {

        if (value == true)
            state = true;
        else state = false;

    }

};

//Размерность матрицы, которую можно задавать

int rows;
int cols;

//Матрица

bool firstRun = true;
someType*** matrix;

//Передача матрицы в функцию

void doSomething(someType*** matrix, int currentRow, int currentCol) {

    matrix[currentRow][currentCol]->setState(true);

}

//Перестройка матрицы

void rebuildMatrix(someType*** matrix, int newRows, int newCols) {

    //Очистка

    if (firstRun == false) {

        for (int i = 0; i < rows; i++) {

            for (int j = 0; j < cols; j++) {

                delete matrix[i][j];

            }

        }

        firstRun = true;

    }

    rows = newRows;
    cols = newCols;

    //Выделение памяти

    matrix = new someType**[rows];

    for (int i = 0; i < rows; i++) {

        matrix[i] = new someType*[cols];

    }

    for (int i = 0; i < rows; i ++) {

        for (int j = 0; j < cols; j++) {

            matrix[i][j] = new someType;

        }

    }

    //Инициализация

    for (int i = 0; i < rows; i++) {

        for (int j = 0; j < cols; j++) {

            matrix[i][j]->setState(false);

        }
    }

}

int main() {

    //Создание матрицы

    rebuildMatrix(matrix, 10, 10);

    //Доступ к элементу матрицы

    matrix[9][9]->setState(true);

    //Вызов функции, в которую передается матрица

    doSomething(matrix, 9, 9);

    //Перестройка матрицы

    rebuildMatrix(matrix, 20, 20);

}
puding
() автор топика

Т.е. здесь

    //Доступ к элементу матрицы

    matrix[9][9]->setState(true);

    //Вызов функции, в которую передается матрица

    doSomething(matrix, 9, 9);

вываливается.

puding
() автор топика
Ответ на: комментарий от comp00

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

Этот топик - просто праздник какой-то.

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

Тьфу,


void setState(bool value) {

        state = value;

    }

Сам поржал )

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

для лечения необходимо провести диагностику.

с какого языка пришёл?(у мя по некоторым кускам кода есть предположения)

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

В школе учили Паскаль, который мне не нравился тем, что не генерировал бинарников. Тогда я решил учить самый мощный язык, как мне показалось, который «может все». Вот, потихоньку быдлокодю. Хоть в математике я «полный NULL», писать все равно нравится.

puding
() автор топика
Ответ на: комментарий от qulinxao

moar

В школе учили Паскаль, который я осилил по книжке за три дня. Сейчас уже забыл. Он мне не нравился тем, что не генерировал бинарников. Тогда я решил учить самый мощный язык, как мне показалось, который «может все». Вот, потихоньку быдлокодю. Хоть в математике я «полный NULL», писать все равно нравится.

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