1

Тема: Двовимірний динамічний масив (додати стовбчик у вказану позицію)

Привіт. Потрібна допомога в наступній задачі
Дано двовимірний масив, розміри якого задає користувач. В даний масив потрібно вставити стовбчик у вказану користувачем позицію. Використовувати можна лише вказівники. Жодних індексів!!!
У мене зациклює функція  copy_arr. Що з нею не так?
Дякую

void init_arr(int *arr, int x_size)
{
    for (int *arr_ptr = arr; arr_ptr < arr + x_size; ++arr_ptr)
    {
        *arr_ptr = rand() % 50 - 25;
    }
}

void arr_initialization(int **arr, int lines, int columns) // ініціалізація масиву
{
    for (int **arr_ptr_ptr = arr; arr_ptr_ptr < arr + lines; ++arr_ptr_ptr)
    {
        *arr_ptr_ptr = new int[columns];
        init_arr(*arr_ptr_ptr, columns);
    }
}


void print_arr(int **arr, int lines, int columns) // друк масиву
{
    for (int **arr_ptr_ptr = arr; arr_ptr_ptr < arr + lines; ++arr_ptr_ptr)
    {
        for (int *arr_ptr = *arr_ptr_ptr; arr_ptr < *arr_ptr_ptr + columns; ++arr_ptr)
        {
            cout << setw(4) << *arr_ptr;
        }
        cout << endl;
    }
}

void copy_arr(int **arr_scr, int lines, int columns, int **arr_dst) //копіювання масиву
{
    for (int **arr_scr_ptr_ptr = arr_scr; arr_scr_ptr_ptr < arr_scr + lines; ++arr_scr_ptr_ptr)
    {
        for (int *arr_scr_ptr = *arr_scr_ptr_ptr; arr_scr_ptr < *arr_scr_ptr_ptr + columns; ++arr_scr_ptr, ++arr_dst)
        {
            *arr_dst = arr_scr_ptr;
            arr_scr_ptr = nullptr;
        }
    }
}

int **add_column_to_arr(int **arr, int lines, int *columns, int index)
{
    int new_size = *columns + 1;
    int **arr_ptr_ptr = new int*[lines];
    for (int y = 0; y < lines; ++y)
    {
        arr_ptr_ptr[y] = new int[new_size];
    }

    copy_arr(arr, lines, index, arr_ptr_ptr);

    copy_arr(arr + index, lines, *columns - index, arr_ptr_ptr + index + 1);

    for (int y = 0; y < lines; ++y)
    {
        arr_ptr_ptr[y][index] = 1;
    }

    *columns = new_size;
    return arr_ptr_ptr;
    for (int y = 0; y < lines; ++y)
        arr_ptr_ptr[y] = new int[*columns];
    clear_arr(arr_ptr_ptr, lines);
}

void task1()
{
    int lines = 0;
    int columns = 0;
    cout << "Array initialization." << endl;
    cout << "Enter number of lines : ";
    cin >> lines;
    cout << "Enter number of columns : ";
    cin >> columns;
    int **dimm2_arr;
    dimm2_arr = new int *[lines];
    for (int i = 0; i < lines; i++)
    {
        dimm2_arr[i] = new int[columns];
    }
    arr_initialization(dimm2_arr, lines, columns);
    print_arr(dimm2_arr, lines, columns);

    int index;
    do
    {
        cout << "Enter the index of column to add : ";
        cin >> index;
    } while (index < 0 || index > columns);

    dimm2_arr = add_column_to_arr(dimm2_arr, lines, &columns, index);
    print_arr(dimm2_arr, lines, columns);

    clear_arr(dimm2_arr, lines);
}

2

Re: Двовимірний динамічний масив (додати стовбчик у вказану позицію)

Вітаю на форумі.

Пара загальних порад:

0. Операції з вказівниками взагалі небезпечні, тому їхню кількість слід мінімізувати, а самі операції обгортати у відповідні функції та структури. Тобто дуже бажано, щоб в main не було жодних вказівників, а тільки виклики відповідних функцій. Ну, то лише побажання.
1. Не працюйте в одній функції з двома рівнями масиву одночасно, надто легко заплутатися.
2. Стежте за відповідністю назв тому, що функції роблять. copy_arr має копіювати масив, а натомість, здається, його переміщує.

Що ж до функції copy_arr, то ви надто заглибилися, дивіться пораду 1. Конкретно проблема в тому, що після arr_scr_ptr = nullptr; умова arr_scr_ptr < *arr_scr_ptr_ptr + columns буде гарантовано виконуватися, і цикл не завершиться.

3 Востаннє редагувалося ntkrnlpa.exe (14.11.2016 08:03:55)

Re: Двовимірний динамічний масив (додати стовбчик у вказану позицію)

якшо я правильно зрозумів завдання, то ось вам правильна C версія. :D
ваш код виявився занадто прогресивним для мене, шоб намагатися його зрозуміти. Я думаю, шо він неправильний. Ні, він точно неправильний. В дуже багатьох місцях, шоб це пояснювати.
Якшо цікаво, подивіться на код нижче. Він працює. Єдине, я не впевнений шо зрозумів завдання точно. Тож, цей код робить те, шо я зрозумів як завдання. Плюс - нашвидкоруч вигадав інтерфейс введення. Ви можете змінити його якшо так бажається.
Програма приймає як правильне введення послідовність з 3-х чисел як аргументи командного рядка, де перше число задає кількість рядків, друге - кількість стовбчиків, третє - позицію в масиві яку треба поміняти, нумерація з нуля! Далі, якшо все правильно введено, програма ініціалізує масив так як ви робили, за допомогою, rand(), лише по модулю 256, просто шоб легше сприймалось на екрані. І просе ввести стовбчик, підказуючи як це зробити. Потім вставляє його і виводить змінений масив.
Для змінних Array і L вибраний тип void *, шоб підкреслити шо це не вказіники на int, насправді Array є вказівником який вказує на наш масив цілих, але логічно це ж двовимірний масив. Тож наш вказівник це просто вказівник на якийсь складний тип. Використання типу int * тут, могло б заплутати.  L - це вказівник власне на рядок цілих. На підмасив тобто. Знову довільний складний об'єкт. Шоб підкреслити це, ми вибираємо генеричний тип вказівника, а потім робимо потрібні приведення. У нас довжини масиву невідомі до часу виконання. Теж треба завважити.
Коментарі написав мовою, схожою на англійську, за інерцією.

▼Прихований текст
#include<stdio.h>
#include<stdlib.h>

int main(int argc, char **argv){
    int    *C, lines, columns, position, length, i, j, x;
    void    *Array, *L;

    /* input check and usage instructions */
    if(argc != 4){
        printf("Usage: %s <lines> <columns> <position>\n", *argv);
        return 0xcacacaca;
    }

    lines        = atoi(*(argv + 1));
    columns        = atoi(*(argv + 2));
    position    = atoi(*(argv + 3));
    length        = lines * columns;

    if(length <= 0 || position >= columns || position < 0){
        printf("Invalid input.\n");
        return 0xcacacaca;
    }

    Array = (void *)malloc(length * sizeof(int)); 
    if(!Array){
        printf("malloc failed.\n");
        return 0xcacacaca;
    }

/* initialize and show the array */
/* L points to the "line item" in the array of lines */
    L = Array;    // first line address, we don't touch Array pointer for the obvious reasons, so we have a copy to work on
    for(i = 0; i < lines; i++){
// here, we initialize C pointer which points to the integer element inside the chosen line
        C = (int *)L;    // first column item in the i-th line
        for(j = 0; j < columns; j++){
            *C = rand() % 0x100;    // asign the integer element some number modulo 256 for readabilty
            if(j == position)
// show the element, we dereference C, this is equivalent to *((int *)Array + i * columns + j)
                printf("\t>%d<", *C);
            else
                printf("\t%d ", *C);
            C++;    // walk through the entire line
        }
/* now we adjust our line pointer to the next line address
 * we cast the pointer to the int pointer, because this way pointer arithmetics is easy. In fact, we just need
 * to adjust the line pointer to point to line length bytes forward, thus columns * sizeof(int) bytes forward.
 */
        L = (int *)L + columns;
        putc(0xa, stdout);
    }

    /* prompt the user to input their column to insert into the array */
    printf("enter your column values (%d numbers, type <Enter> after each to proceed).\n", lines);

    L = Array;
    for(i = 0; i < lines; i++){
        C = (int *)L + position;
        scanf("%d", &x);
        *C = x;
        L = (int *)L + columns;
    }

    printf("modified array:\n");
    L = Array;
    for(i = 0; i < lines; i++){
        C = (int *)L;
        for(j = 0; j < columns; j++){
            if(j == position)
                printf("\t>%d<", *C);
            else
                printf("\t%d ", *C);
            C++;
        }
        L = (int *)L + columns;
        putc(0xa, stdout);
    }
    free(Array);
    return 0;
}

А це скорочена версія, яка робить те саме, просто можливо буде наочніше. Правда не знаю, чи потрактується вона як "без індексів", бо хто зна шо саме мали на увазі даючи таке обмеження.

▼Прихований текст
#include<stdio.h>
#include<stdlib.h>

int main(int argc, char **argv){
    int    lines, columns, position, i, j;
    void    *Array;

    if(argc != 4){
        printf("Usage: %s <lines> <columns> <position>\n", *argv);
        return 0xcacacaca;
    }

    lines        = atoi(*(argv + 1));
    columns        = atoi(*(argv + 2));
    position    = atoi(*(argv + 3));

    if(lines * columns <= 0 || position >= columns || position < 0){
        printf("Invalid input.\n");
        return 0xcacacaca;
    }

    Array = (void *)malloc(lines * columns * sizeof(int));
    if(!Array){
        printf("malloc failed.\n");
        return 0xcacacaca;
    }

    for(i = 0; i < lines; i++){
        for(j = 0; j < columns; j++){
            *((int *)Array + i * columns + j) = rand() % 0x100;
            if(j == position)
                printf("\t>%d<", *((int *)Array + i * columns + j));
            else
                printf("\t%d ", *((int *)Array + i * columns + j));
        }
        putc(0xa, stdout);
    }

    printf("enter your column values (%d numbers, type <Enter> after each to proceed).\n", lines);
    for(i = 0; i < lines; i++){
        scanf("%d", &j);
        *((int *)Array + i * columns + position) = j;
    }

    printf("modified array:\n");
    for(i = 0; i < lines; i++){
        for(j = 0; j < columns; j++){
            if(j == position)
                printf("\t>%d<", *((int *)Array + i * columns + j));
            else
                printf("\t%d ", *((int *)Array + i * columns + j));
        }
        putc(0xa, stdout);
    }
    free(Array);
    return 0;
}

4

Re: Двовимірний динамічний масив (додати стовбчик у вказану позицію)

Привіт. Забув вказати, що мова програмування С++.
ntkrnlpa.exe, у вас в коді використовуються індекси
for(i = 0; i < lines; i++); таким способом я цю задачу зробив без особливих проблем.
На жаль, індекси використовувати не дозволяється, тому потрібно робити все через вказівники
for(int **arr_ptr = arr; arr_ptr = arr + lines; ++arr_ptr)
де **arr_ptr - вказівник на масив вказівників
arr - вказівкник на двовимірний масив

Думаю, що я майже зрозумів в чому проблема і сьогодні на свіжу голову спробую поправити код.

5 Востаннє редагувалося boshik1983 (14.11.2016 23:29:44)

Re: Двовимірний динамічний масив (додати стовбчик у вказану позицію)

Зробив. Все працює. Але є питання: чи можна оптимізувати даний код?

#include<iostream>
#include<iomanip>
#include<time.h>

using namespace std;


void init_arr(int *arr, int x_size) //ініціалізація змінних в рядку
{
    for (int *arr_ptr = arr; arr_ptr < arr + x_size; ++arr_ptr)
    {
        *arr_ptr = rand() % 50 - 25;
    }
}

void arr_initialization(int **arr, int lines, int columns) //ініціалізація масиву
{
    for (int **arr_ptr_ptr = arr; arr_ptr_ptr < arr + lines; ++arr_ptr_ptr)
    {
        *arr_ptr_ptr = new int[columns];
        init_arr(*arr_ptr_ptr, columns);
    }
}


void print_arr(int **arr, int lines, int columns) //вивід масиву на екран
{
    for (int **arr_ptr_ptr = arr; arr_ptr_ptr < arr + lines; ++arr_ptr_ptr)
    {
        for (int *arr_ptr = *arr_ptr_ptr; arr_ptr < *arr_ptr_ptr + columns; ++arr_ptr)
        {
            cout << setw(4) << *arr_ptr;
        }
        cout << endl << endl;
    }
}


void clear_arr(int **arr, int lines) //видалення масиву
{
    for (int **arr_ptr_ptr = arr; arr_ptr_ptr < arr + lines; ++arr_ptr_ptr)
    {
        delete[] * arr_ptr_ptr;
    }
    delete[] arr;
}


//Написать функцию, добавляющую столбец двухмерному массиву в указанную позицию.
void add_column(int **scr, const int lines, const int columns, int **dst, const int index)
{
    for (int **scr_ptr = scr, **dst_ptr = dst; scr_ptr < scr + lines; ++scr_ptr, ++dst_ptr) //проходимося по ігрикам
    {
        for (int *scr_ptr_2 = *scr_ptr, *dst_ptr_2 = *dst_ptr; scr_ptr_2 < *scr_ptr + columns;) //проходимося по іксам
        {
            for (; scr_ptr_2 < *scr_ptr + index; ++scr_ptr_2, ++dst_ptr_2) //копіюємо значення по іксу від початку до індекса
            {
                *dst_ptr_2 = *scr_ptr_2;
            }
            *dst_ptr_2 = 1; // ініціалізація змінної індекса (можна і написати, щоб користувач вводив, або рандомно)
            ++dst_ptr_2; // переходимо до наступного ікса, щоб не скопіювати значення в індекс повторно
            for (; scr_ptr_2 < *scr_ptr + columns; ++scr_ptr_2, ++dst_ptr_2) //копіюємо значення по іксу від індекса до кінця
            {
                *dst_ptr_2 = *scr_ptr_2;
            }
        }
    }
}

int **add_column_to_arr(int **arr, int lines, int *columns, int index)
{
    int new_size = *columns + 1;
    int **arr_dst = new int*[lines];
    for (int **arr_ptr = arr_dst; arr_ptr < arr_dst + lines; ++arr_ptr)
    {
    *arr_ptr = new int[new_size];//створюємо масив на один ствпчик більший існуючого
    }

    add_column(arr, lines, *columns, arr_dst, index);
    *columns = new_size; //присвоюємо змінній нове значення, а масиву, відповідно, новий розмір
    return arr_dst;
    clear_arr(arr_dst, lines); //не забуваємо очистити пам'ять
}

void task1()
{
    int lines = 0;
    int columns = 0;
    cout << "Array initialization." << endl;
    cout << "Enter lines quantity : ";
    cin >> lines;
    cout << "Enter columns quantity : ";
    cin >> columns;
    int **dimm2_arr;
    dimm2_arr = new int *[lines];

    arr_initialization(dimm2_arr, lines, columns);
    print_arr(dimm2_arr, lines, columns);

    int index;
    do
    {
        cout << "Enter the index of column to add : ";
        cin >> index;
    } while (index < 0 || index > columns);

    dimm2_arr = add_column_to_arr(dimm2_arr, lines, &columns, index);
    print_arr(dimm2_arr, lines, columns);

    clear_arr(dimm2_arr, lines);
}

6 Востаннє редагувалося ntkrnlpa.exe (15.11.2016 13:42:12)

Re: Двовимірний динамічний масив (додати стовбчик у вказану позицію)

boshik1983 написав:

Привіт. Забув вказати, що мова програмування С++.
ntkrnlpa.exe, у вас в коді використовуються індекси
for(i = 0; i < lines; i++);
таким способом я цю задачу зробив без особливих проблем.
На жаль, індекси використовувати не дозволяється, тому потрібно робити все через вказівники

Думаю, що я майже зрозумів в чому проблема і сьогодні на свіжу голову спробую поправити код.

Ну який же це індекс, це лічильник цикла. :D

for(int **arr_ptr = arr; arr_ptr = arr + lines; ++arr_ptr)
де **arr_ptr - вказівник на масив вказівників
arr - вказівкник на двовимірний масив

Тут таке діло, якшо arr і справді був би "вказівником на двовимірний масив", тобто шось оголошене як
int arr[n][m]; ваш код не працював би. Навіть оцей шматок циклу вище був би глибоко неправильним. arr у вас такий же вказівник на вказівник на тип int як і arr_ptr, і ви його просто безглуздо копіюєте, хоча оскільки то аргумент переданий в функцію, яких ви наклепали невідомо нашо стільки, ви б могли його викорситовувати прямо. це вам оптимізація. а взагалі переробіть його - занадто багато непотрібних функцій.
чесно, розібратися в вашому коді майже неможливо.
Дивіться, а так - "без індексів"?

▼Прихований текст
#include<stdio.h>
#include<stdlib.h>

int main(int argc, char **argv){
    int    *L, *C, lines, columns, position, Z;
    void    *Array;

    if(argc != 4){
        printf("Usage: %s <lines> <columns> <position>\n", *argv);
        return 0xcacacaca;
    }

    lines        = atoi(*(argv + 1));
    columns        = atoi(*(argv + 2));
    position    = atoi(*(argv + 3));

    if(lines * columns <= 0 || position >= columns || position < 0){
        printf("Invalid input.\n");
        return 0xcacacaca;
    }

    Array = (void *)malloc(lines * columns * sizeof(int));
    if(!Array){
        printf("malloc failed.\n");
        return 0xcacacaca;
    }

    for(L = (int *)Array; L < (int *)Array + columns * lines; L += columns){
        for(C = L; C < L + columns; C++){
            *C = rand() % 0x100;
            printf("\t%d", *C);
        }
        putc(0xa, stdout);
    }

    printf("enter your column values (%d numbers, type <Enter> after each to proceed).\n", lines);
    for(L = (int *)Array + position; L < (int *)Array + columns * lines; L += columns){
        scanf("%d", &Z);
        *L = Z;
    }

    printf("modified array:\n");
    for(L = (int *)Array; L < (int *)Array + columns * lines; L += columns){
        for(C = L; C < L + columns; C++)printf("\t%d", *C);
        putc(0xa, stdout);
    }
    free(Array);
    return 0;
}