Ошибки адресации массивов

plzvtl

57 / 43 / 12

Регистрация: 27.10.2018

Сообщений: 452

1

MASM32

Ошибка при адресации элементов массива при адресации

03.11.2020, 20:52. Показов 1187. Ответов 10

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Задание: вычислить значение заданной функции :
if (c>d) X=(8* lg(d+1) - c)/(a / 2 + d * c) else X=(4*c-ln(d-1))/(a/d+18)
но проблема в том что я где-то в асм модуле допустил ошибку при адресации и результат записывает некорректно.
Подозрение на строки:

Assembler
1
2
        mov esi, dword ptr[ebp + 8] 
        mov edi, dword ptr[ebp + 32]
Assembler
1
        fstp qword ptr [edi + 8 * ecx]
Assembler
1
        fld qword ptr [esi + 8 * ecx]

но я немогу понять где ошибка и как это пофиксить, помогите пожалуйста, спасибо заранее.
Код:
asm модуль:

Assembler
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
.586
.model flat,c 
 PUBLIC calc 
.data
        const1  REAL8   1.0
        const2  REAL8   2.0
        const3  REAL8   4.0
        const4  REAL8   8.0
        const6  REAL8   18.0
        temp    REAL8   ?
 
 
        ;dword ptr[ebp + 0] return
        ;dword ptr[ebp + 4] ebp
        ;dword ptr[ebp + 8]  double * a (dd)
        ;dword ptr[ebp + 12] double c
        ;dword ptr[ebp + 20] double d
        ;dword ptr[ebp + 28] n
        ;dword ptr[ebp + 32] double * r (dd)
 
.code
    calc proc
        push ebp
        mov ebp, esp
        finit
        mov esi, dword ptr[ebp + 8] 
        mov edi, dword ptr[ebp + 32] 
        mov ecx, dword ptr[ebp + 28] 
        dec ecx
        fld qword ptr [ebp+ 12]
        fcomp qword ptr [ebp + 20]
        fstsw ax
        sahf
        jbe els1  ;if C<=D
 
    @@__cycle:
        fld qword ptr [ebp + 20]
        fadd const1
        fstp temp
        FLD1
        FLD  temp
        FYL2X              ; st =  log2(X)
        FLDL2T             ; st =  log2(10)
        FDIVP st(1), st(0) ; st =  log10(X)
        fmul const4
        fsub qword ptr [ebp + 12]
        fld qword ptr [esi + 8 * ecx]
        fdiv const2
        fld qword ptr [ebp + 12]
        fmul qword ptr [ebp + 20]
        fadd 
        fdivr st(0), st(1)
        fstp qword ptr [edi + 8 * ecx]
.if (ecx == 1)
        jmp rez
.endif
        dec ecx
        jmp @@__cycle
 
    els1:   
 
    @@__cycle2:
        fld  qword ptr [ebp + 20]
        fsub const1
        fstp temp 
        fldln2
        fld temp
        fyl2x
        fld  qword ptr [ebp + 12]
        fmul const3
        fsub st(0),st(1)
 
        fld qword ptr [esi + 8 * ecx]
        fdiv qword ptr [ebp + 20]
 
        fadd const6
        fdivr st(0), st(1)
        fstp qword ptr [edi + 8 * ecx]
.if (ecx == 1)
        jmp rez
.endif
        dec ecx
        jmp @@__cycle2
 
    rez: 
        pop ebp
        ret
    calc endp
end

c++ модуль:

C++
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
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <conio.h>
#include <cmath>
#include <iostream>
#include <iomanip>
extern "C" double*  calc(double * A, double C, double D, unsigned long int n, double * R);
signed long int n;
void main(void)
{
 
    float C, D;
    double c, d;
 
    std::cout << "if (c>d) X=(8* lg(d+1) - c)/(a / 2 + d * c) else X=(4*c-ln(d-1))/(a/d+18) n" << " enter c:n";
    std::cin >> c;
    std::cout << " enter d:n";
    std::cin >> d;
 
    while (((c - d) > 0.0000000000000001) && ((d + 1) <= 0) || ((c - d) <= 0.0000000000000001) && ((d - 1) <= 0))
    {
        std::cout << "log from neg or 0nreenter c:n";
        std::cin >> c;
        std::cout << "reenter d:n";
        std::cin >> d;
    }
 
    std::cout << "Enter n:n";
    std::cin >> n;
    while (0 >= n) {
        std::cout << "nreenter nn";
        std::cin >> n;
    }
    double * A = new double[n];
    double * R = new double[n];
    {
        signed long int n = ::n;
        while (0 != n--) {
            std::cout << "Enter A[" << n << "]:n";
            std::cin >> A[n];
        }
    }
    unsigned long int i = n;
    while (0 != i--)
    {
        if (((c - d) > 0.0000000000000001))
        {
            std::cout << "Result " << i << " in c is: ";
            if (((d + 1) > 0) && (0 != (*(A + i) / 2 + d * c))) std::cout << std::dec << std::setprecision(16) << (8 * std::log10((double)d + 1) - (double)c) / (A[i] / 2 + (double)d * (double)c) << 'n';
            else if (0 == (*(A + i) / 2 + d * c)) std::cout << "div with 0n";
        }
        else {
            if (((c - d) <= 0.0000000000000001) && (0 != (*(A + i) / d + 18)))std::cout << std::dec << std::setprecision(16) << "Result " << i << " in c is " << (4 * (double)c - std::log((double)d - 1)) / (A[i] / (double)d + 18) << 'n';
            else if (0 == (*(A + i) / d + 18)) std::cout << "div with 0n";
        }
    }
    calc(&*(A + 0), (double)c, (double)d, ::n, &*(R + 0));
    i = n;
    while (0 != i--) std::cout << "Result " << i << " in asm is: " << std::dec << std::setprecision(16) << *(R + i) << std::endl;
    delete[] A;
    delete[] R;
    _getch();
}



0



plzvtl

57 / 43 / 12

Регистрация: 27.10.2018

Сообщений: 452

03.11.2020, 21:02

 [ТС]

2

дизассемблер и вывод :

Assembler
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
push ebp
011540C0  push        ebp  
        mov ebp, esp
011540C1  mov         ebp,esp  
        finit
011540C3  wait  
011540C4  fninit  
        mov esi, dword ptr[ebp + 8] 
011540C6  mov         esi,dword ptr [ebp+8]  
        mov edi, dword ptr[ebp + 32] 
011540C9  mov         edi,dword ptr [ebp+20h]  
        mov ecx, dword ptr[ebp + 28] 
011540CC  mov         ecx,dword ptr [ebp+1Ch]  
        dec ecx
011540CF  dec         ecx  
        fld qword ptr [ebp+ 12]
011540D0  fld         qword ptr [ebp+0Ch]  
        fcomp qword ptr [ebp + 20]
011540D3  fcomp       qword ptr [ebp+14h]  
        fstsw ax
011540D6  wait  
011540D7  fnstsw      ax  
        sahf
011540D9  sahf  
        jbe els1  ;if C<=D
011540DA  jbe         @@__cycle+46h (01154122h)  
 
    @@__cycle:
        fld qword ptr [ebp + 20]
011540DC  fld         qword ptr [ebp+14h]  
        fadd const1
011540DF  fadd        qword ptr [const1 (0115E010h)]  
        fstp temp
011540E5  fstp        qword ptr [temp (0115E038h)]  
        FLD1
011540EB  fld1  
        FLD  temp
011540ED  fld         qword ptr [temp (0115E038h)]  
        FYL2X              ; st =  log2(X)
011540F3  fyl2x  
        FLDL2T             ; st =  log2(10)
011540F5  fldl2t  
        FDIVP st(1), st(0) ; st =  log10(X)
011540F7  fdivp       st(1),st  
        fmul const4
011540F9  fmul        qword ptr [const4 (0115E028h)]  
        fsub qword ptr [ebp + 12]
011540FF  fsub        qword ptr [ebp+0Ch]  
        fld qword ptr [esi + 8 * ecx]
01154102  fld         qword ptr [esi+ecx*8]  
        fdiv const2
01154105  fdiv        qword ptr [const2 (0115E018h)]  
        fld qword ptr [ebp + 12]
0115410B  fld         qword ptr [ebp+0Ch]  
        fmul qword ptr [ebp + 20]
0115410E  fmul        qword ptr [ebp+14h]  
        fadd 
01154111  faddp       st(1),st  
        fdivr st(0), st(1)
01154113  fdivr       st,st(1)  
        fstp qword ptr [edi + 8 * ecx]
01154115  fstp        qword ptr [edi+ecx*8]  
.if (ecx == 1)
01154118  cmp         ecx,1  
0115411B  jne         @@__cycle+43h (0115411Fh)  
        jmp rez
0115411D  jmp         @@__cycle+85h (01154161h)  
.endif
        dec ecx
0115411F  dec         ecx  
        jmp @@__cycle
01154120  jmp         @@__cycle (011540DCh)  
 
    els1:   
 
    @@__cycle2:
        fld  qword ptr [ebp + 20]
01154122  fld         qword ptr [ebp+14h]  
        fsub const1
01154125  fsub        qword ptr [const1 (0115E010h)]  
        fstp temp 
0115412B  fstp        qword ptr [temp (0115E038h)]  
        fldln2
01154131  fldln2  
        fld temp
01154133  fld         qword ptr [temp (0115E038h)]  
        fyl2x
01154139  fyl2x  
        fld  qword ptr [ebp + 12]
0115413B  fld         qword ptr [ebp+0Ch]  
        fmul const3
0115413E  fmul        qword ptr [const3 (0115E020h)]  
        fsub st(0),st(1)
01154144  fsub        st,st(1)  
 
        fld qword ptr [esi + 8 * ecx]
01154146  fld         qword ptr [esi+ecx*8]  
        fdiv qword ptr [ebp + 20]
01154149  fdiv        qword ptr [ebp+14h]  
 
        fadd const6
0115414C  fadd        qword ptr [const6 (0115E030h)]  
        fdivr st(0), st(1)
01154152  fdivr       st,st(1)  
        fstp qword ptr [edi + 8 * ecx]
01154154  fstp        qword ptr [edi+ecx*8]  
.if (ecx == 1)
01154157  cmp         ecx,1  
0115415A  jne         @@__cycle+82h (0115415Eh)  
        jmp rez
0115415C  jmp         @@__cycle+85h (01154161h)  
.endif
        dec ecx
0115415E  dec         ecx  
        jmp @@__cycle2
0115415F  jmp         @@__cycle+46h (01154122h)  
 
    rez: 
        pop ebp
01154161  pop         ebp  
        ret
01154162  ret

Миниатюры

Ошибка при адресации элементов массива при адресации
 



0



E=m*c^2

160 / 47 / 10

Регистрация: 04.02.2019

Сообщений: 261

Записей в блоге: 5

04.11.2020, 08:00

3

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

Добавлено через 31 секунду
х32 зло, переходи на векторный х64

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



0



ФедосеевПавел

Модератор

Эксперт по электронике

8316 / 4215 / 1602

Регистрация: 01.02.2015

Сообщений: 13,125

Записей в блоге: 4

04.11.2020, 09:17

4

plzvtl, думаю, что требуется пояснение — почему функция заполняет массив.
Да и тестовую программу на C++ упростить до отсутствия какого-либо ввода.

Ещё, хоть и не знаю C++, кажется странной такая передача адреса в функцию

C++
57
calc(&*(A + 0), (double)c, (double)d, ::n, &*(R + 0));

ведь A это динамический массив, т.е. указатель на массив (область памяти), т.е. переменная A содержит адрес на массив.

Судя по скриншоту, заполнение массива на ассемблере совпало с заполнением оного на C++ кроме одного элемента. Видимо, одна из веток вычисляется некорректно или ошибка в переходе на другую ветку.
Т.е. нужно проверить условие ветвления.



0



57 / 43 / 12

Регистрация: 27.10.2018

Сообщений: 452

04.11.2020, 11:01

 [ТС]

5

Цитата
Сообщение от K_ILYA_V
Посмотреть сообщение

ты изменяешь значения esi edi, этого делать нельзя

Почему нельзя?

Цитата
Сообщение от K_ILYA_V
Посмотреть сообщение

ты можешь вернуть из функции сразу double, для этого его нужно оставить на вершине стека сопроцесора, это место передачи результата с плавающей точкой, такоеже как eax для целочисленных результатов.

это я знаю, только вернуть мне надо массив чисел. Кроме того размерность массива может изменяться. Вызов асм модуля для каждого числа мне неподходит — сказано сделать 1 вызовом.

Цитата
Сообщение от K_ILYA_V
Посмотреть сообщение

х32 зло, переходи на векторный х64

Сменить платформу? Увы немогу.

Цитата
Сообщение от ФедосеевПавел
Посмотреть сообщение

Ещё, хоть и не знаю C++, кажется странной такая передача адреса в функцию

Есть переменная — указатель, я сместил на 0 байт указатель, разыменовал, и после взял адрес от результата операции.
По сути получил тот же адрес.
Таки запустил передавая просто A, ничего не поменялось.



0



plzvtl

57 / 43 / 12

Регистрация: 27.10.2018

Сообщений: 452

04.11.2020, 11:24

 [ТС]

6

Кроме того если я в асм модуль, в начало цикла подсчета вставлю это

Assembler
1
2
3
4
5
6
7
8
9
        b:
        fld qword ptr[esi + 8 * ecx]
        fstp qword ptr[edi + 8 * ecx]
 
.if(ecx == 0)
        jmp forw
.endif
        dec ecx
        jmp b

то пишет результат как надо.

Миниатюры

Ошибка при адресации элементов массива при адресации
 



0



57 / 43 / 12

Регистрация: 27.10.2018

Сообщений: 452

04.11.2020, 11:51

 [ТС]

7

Кажется я нашел где ошибка, но как пофиксить все еще не понимаю.

Миниатюры

Ошибка при адресации элементов массива при адресации
 

Ошибка при адресации элементов массива при адресации
 



0



Constantin Cat

3405 / 1824 / 489

Регистрация: 28.02.2015

Сообщений: 3,699

04.11.2020, 12:19

8

Цитата
Сообщение от plzvtl
Посмотреть сообщение

Почему нельзя?

Потому, что используются в вызвающем Вашу вставку коде

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.text:00401280 start           proc near
.text:00401280 
.text:00401280 var_38          = dword ptr -38h
.text:00401280 var_1C          = dword ptr -1Ch
.text:00401280 
.text:00401280                 sub     esp, 1Ch
.text:00401283                 mov     [esp+1Ch+var_1C], 1
.text:0040128A                 call    ds:__set_app_type
.text:00401290                 call    loc_401000
.text:00401295                 lea     esi, [esi+0]
.text:00401299                 lea     edi, [edi+0]
.text:004012A0                 sub     esp, 1Ch
.text:004012A3                 mov     [esp+38h+var_38], 2
.text:004012AA                 call    ds:__set_app_type
.text:004012B0                 call    loc_401000
.text:004012B5                 lea     esi, [esi+0]
.text:004012B9                 lea     edi, [edi+0]
.text:004012B9 start           endp

Правильно так:

Assembler
1
2
3
4
5
6
7
8
9
10
.text:004276C0                 push    esi
.text:004276C1                 push    ebx
. . .
.text:004276D1                 mov     ebx, ds:dword_4C87C4
. . .
.text:004276ED                 mov     esi, eax
. . .
.text:0042771D                 pop     ebx
.text:0042771E                 pop     esi
.text:0042771F                 retn



0



plzvtl

57 / 43 / 12

Регистрация: 27.10.2018

Сообщений: 452

05.11.2020, 15:53

 [ТС]

9

Constantin Cat, хорошо, я понял. Сделал так:

Кликните здесь для просмотра всего текста

Assembler
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
.586
.model flat,c 
 PUBLIC calc 
.data
        const1  REAL8   1.0
        const2  REAL8   2.0
        const3  REAL8   4.0
        const4  REAL8   8.0
        const6  REAL8   18.0
        temp    REAL8   ?
 
 
        ;dword ptr[ebp + 0] return
        ;dword ptr[ebp + 4] ebp
 
        ;dword ptr[ebp + 8] esi
        ;dword ptr[ebp + 12] edi
        ;dword ptr[ebp + 16] ebx
 
 
        ;dword ptr[ebp + 8] double * a (dd)    
        ;dword ptr[ebp + 12] double c
        ;dword ptr[ebp + 20] double d
        ;dword ptr[ebp + 28] n
        ;dword ptr[ebp + 32] double * r (dd)
 
.code
    calc proc
        push ebp
        mov ebp, esp
        push esi
        push edi
        push ebx
        finit
        mov esi, dword ptr[ebp + 8] 
        mov edi, dword ptr[ebp + 32] 
        mov ecx, dword ptr[ebp + 28] 
        dec ecx
        fld qword ptr [ebp+ 12]
        fcomp qword ptr [ebp + 20]
        fstsw ax
        sahf
        jbe els1  ;if C<=D
    @@__cycle:
        fld qword ptr [ebp + 20]
        fadd const1
        fstp temp
        FLD1
        FLD  temp
        FYL2X              ; st =  log2(X)
        FLDL2T             ; st =  log2(10)
        FDIVP st(1), st(0) ; st =  log10(X)
        fmul const4
        fsub qword ptr [ebp + 12]
        fld qword ptr [esi + 8 * ecx]
        fdiv const2
        fld qword ptr [ebp + 12]
        fmul qword ptr [ebp + 20]
        fadd 
        fdivr st(0), st(1)
        fstp qword ptr [edi + 8 * ecx]
.if (ecx == 0)
        jmp rez
.endif
        dec ecx
        jmp @@__cycle
    els1:   
    @@__cycle2:
        fld  qword ptr [ebp + 20]
        fsub const1
        fstp temp 
        fldln2
        fld temp
        fyl2x
        fld  qword ptr [ebp + 12]
        fmul const3
        fsub st(0),st(1)
        fld qword ptr [esi + 8 * ecx]
        fdiv qword ptr [ebp + 20]
        fadd const6
        fdivr st(0), st(1)
        fstp qword ptr [edi + 8 * ecx]
.if (ecx == 0)
        jmp rez
.endif
        dec ecx
        jmp @@__cycle2
    rez: 
    forw:
        pop ebx
        pop edi
        pop esi
        pop ebp
        ret
    calc endp
end

обостряю внимание на:

Assembler
1
2
3
4
    
push esi
push edi
push ebx

Assembler
1
2
3
4
    
        pop ebx
        pop edi
        pop esi

Но я уже ничего не понимаю как это

не

работает:
Первое:
При кол-ве элементов массива меньше или равно 6 — всё работает как надо.
Но если ввести n = 7 то всё опять как было.

Миниатюры

Ошибка при адресации элементов массива при адресации
 



0



ФедосеевПавел

Модератор

Эксперт по электронике

8316 / 4215 / 1602

Регистрация: 01.02.2015

Сообщений: 13,125

Записей в блоге: 4

05.11.2020, 20:45

10

plzvtl, сохраните где-нибудь код и начните заново.
Начните с последовательного усложнения кода
1. итоговый массив — удвоенный входной

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.686
.model flat, c
option casemap :none
 
FillArray   proc    lpSrcArray:dword, lfC:REAL8, lfD:REAL8,
            nSize:dword, lpDstArray:dword
    mov esi,    [lpSrcArray]
    mov edi,    [lpDstArray]
    mov ecx,    [nSize]
    finit
    @@for:
        fld     qword ptr[esi]
        fstp    qword ptr[edi]
        add esi,    8
        add edi,    8
    loop    @@for
    ret
FillArray   endp
 
end

2. далее добавляете условие и какое нибудь действие над элементом массива

Assembler
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
.686
.model flat, stdcall
option casemap :none
 
FillArray   proc    lpSrcArray:dword, lfC:REAL8, lfD:REAL8,
            nSize:dword, lpDstArray:dword
    mov esi,    [lpSrcArray]
    mov edi,    [lpDstArray]
    mov ecx,    [nSize]
    finit
    fld qword ptr[lfC]
    fld qword ptr[lfD]
    @@for:
        fcomi   st(0),  st(1)
        jb  @@else
        @@then:
        ;c<=d
            fld qword ptr[esi]
            jmp @@next
        @@else:
        ;c>d
            fld qword ptr[esi]
 
    @@next:
        fstp    qword ptr[edi]
        add esi,    8
        add edi,    8
    loop    @@for
    ret
FillArray   endp
 
end

И так усложняя понемногу создадите правильный код.

Затем определите имена параметров в виде констант

Assembler
1
nSize equ dword ptr [ebp+1Ch]

и добавите ручное создание фрейма стека и сохранение регистров.



0



plzvtl

57 / 43 / 12

Регистрация: 27.10.2018

Сообщений: 452

06.11.2020, 21:03

 [ТС]

11

Решил проблему. Добавил строки

Assembler
1
2
fstp st(0)
fstp st(0)

в код з поста №1 после строки 78 и строки 53.



1



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

Определить, имеются ли два пассажира, багаж которых совпадает по числу вещей и различается по весу нс более чем на р кг. Выяснить, имеется ли пассажир, багаж которого состоит из р, вещей весом не менее ря кг. Дать сведения о пассажирах, число вещей которых не меньше, чем в любом другом багаже, а вес вещей нс больше, чем в любом другом багаже с этим же числом вещей. Выяснить, имеется ли пассажир„багаж которого превышает багаж каждого из остальных пассажиров и по числу вещей н по ассу. Выяснить, имеются ли в школе однофамильцы. Выяснить, имеются лн однофамильцы в каких-либо параллельных классах. Выяснить, имеются ли однофамильцы в каком-нибудь классе.

43.* Выяснить, в каком классе учится максимальное число учениц. 44. Выяснить, на сколько учеников в р-х классах школы больше, чем в десятых. 45.* Найти среднее число учениц в классах школы. 46.в Найти классы, в которых число учеников больше числа учениц. 47. Найти классы, выпускники которых либо поступили в вузы, либо служат в армии. Литература к заданию ‘Л 1. Кристиан К. Введение в операционную систел!и !Л~ПХ. — Л1: Финансы и стапшспшка, 1985.

Беляков ИН., Рабовер ЮИ., Фридман Л.у! Л!обильная операционная система: Справочник..-Л!.: Радио и связь, 1991. 3. Баурн С. Отрационная систеча БЛ1Х Л1: Мир, 1986. 4. СП Снь!ПРазса!. Краткое руководсгпвоззЗайцев В.Е., Лебедев А В., Сошников Д В. Мл МАИ, 1997 2003. 5. Неясен К., Вирт Н. Паскаль. Руководство пользователя и описание языка.

— М: Финансы и тнатистика, !980, 1989. 6. Абралнзв СА. и др. Задачи по програлсиированию. — Л1: Наука, !988. 7. Пичыциков В.Н. Сборник упралснений по языку Паскаль. -.М: Наука, 1989. 8. Зайцев В Е. и др. СТ)-хреспюлгапшя по к~усу Информатика. М: МАИ 1997 2004. 9. Дейт. Введение в сисгпемы баз данных. — Л1: Наука, 1981. !О. Каймин ВА., Титов В.К., и др. Информатика. Учебное пособие и сборник заоач срешениялш (для школьникое). Л!.: Бридлс, 1994 1!. Технология программирования. 1995, Лй! (март). Журнал для профессиональных про ршилшстов с прилозкениел( С!з-КОЛЛ! (имеется в продазюе в киоске Л!АИ ц. 35 рл), 12. Дейтел 1 .

‘Введение в операционные ситпемы. Т.2. — Мл Мир, 1987. Вопросы для самостоятельного изучения к заданию 17П курсового проекта и к лабораторной работе №21 РАЗРЕЖЕННЫЕ МАТРИЦЫ 1. Представление массивов в памяти ЭВМ. 2. Адрес щия элементов массивов и сс использование для представления структур данных. 3. Передача параметров-массивов и параметров-записей.

4. Ошибки адресации массивов и их последствия при выполнении программ в операционных системах с зшцитой памяти и бсэ нее. 5. Приемы обработки и ввода/вывода массивов на скалярных ЭВМ. 6. Представление обычных и вариантных записей в памяти ЭВМ. 7. Приемы обработки и ввода/вывода записей. 8. Разреженные матрицы. Их представление в памяти ЭВМ. 9.

Особенности хранения в памяти ЭВМ треугольных, симметричных и квазидиагональных матриц. 10. Приемы хранения и обработки разреженньж матриц на языках Паскаль и Си. ОС 1)Ь!1Х. ПРОГРАММИРОВАНИЕ НА ИКЯ. !. Понятие о программировании на ИКЯ (бйсП.Сзйс11, Ьавй, рог!, …). Командные файлы и процедуры. 2. ИКЯ ОС )Лч)1Х (бйе11.

Свйе!1, Ьав1ь )гвйе11, хз1ге!1, …). 3. ИКЯ общего назначения (ЙЕХХ. рег1, …). Основные консгпрукции и приемы програлгиирования на одном из ИКЯ, по выбору преподавателя в группе. 1. Переменные. Присваивание. Понятие окружения. 2. Использование параметров в командных файлах и процедурах. 3. Интерпретация команд. Подстановка переменных и комацд. Встроенные документы. 4. Вычисление выражений. 5. Проверки и ветвления. 6. Циклы. 7.

Оператор выбора Задача Ъ’11. Разреженные матрицы. Составить програгял~у на Паскале (на Си) с процедурами и!или функциями для обработки прлмоу. альных разреженных матриц с элементами целого (группы 1. 2, 3. 9). вещественного (группы 4, 5. 7), или комплексного (группы 6, 8) типов, которая: 1. вводит матрицы различного размера представленные во входном текстовом файле в обычном формате (по строкам). с одновременным размещением ненулевых элементов в разреженной матрице в соответствии с заданной схемой: 2. печатает введенные матрицы во внутреннем представлении согласно заданной схеме ра)мещения и в обычном (естественном) виде; 3.

выполняет необходимыс преобразования разреженных матриц (или вычисления над ними) путем обращения к соответствующим процедурам игили функциям; 4. печатает результат преобразования (вычисления) согласно заданной схеме размещения и в обычном виде. В процедурах и функциях предусмотреть проверки и печать сообщсиий в случаях ошибок в задании параметров. Для отладки использовать матрицы. содержащие 5 — 10% ненулевых элементов с максимальным числом элементов 100.

Вариант схемы размещения матрицы определяется по формуле ((ггг з- 3) шо(1 4) ж 1, где Аг — номер студента по списку в группе. Вариант преобразования определяется по формуле ((Х вЂ” 1) шо(1 11) -г 1. Вариант физического предспаления (1— отображение на массив, 2 — отображение на динамические структуры) определяются по формуле (11 5 х((3+Лз) шо(! 9)) +Л) апой 2+1, где ЛХ вЂ” номер группы. В случае использования динамических структур индексы заменяются соответствующими ссылками. Варианты схемы размещения матрицы: все матрицы т х п хранятся по строите, в порядке возрастания индексов ненулевых элементов.

1. епочка не .левых элементов в некто еЛ со ст очным и екси ованием (индексы в массивеМравны О, если соответствующая строка матрицы содержит только нули) М: Индекс начала 1-ой строки Иипекс начала 3-й … Иннекс начала М-ой в массиве А с окн Ст оки А Помер сголбца Значение Иннекс сленующего !1омер столбца Значение ненулевого элемента этой от окн (илло) Индекс следующего ненулевого элемента этой строки (или 0) 0 Номер Номер Значение Номер Значение ст оки столбца столбца 0 Номер Номер Значение ст оки столбца 0 0 г.тр р: Индекс начали 1-ой строки в массивах Р! и ггЕ Индекс начарла 2-ой Ст ки Индекс начала )г(-ой С ки Р1: Номер Номер Номер Номер 0 столбца столбца столбца Столбца г’Е: Значение Значение Значение Значение р.

~~зн )В: )й’ Аг А1 т’Е: Значение Значение Значение Значение где )мэ = (1 — 1) х и ь) — 1 !!о согласованию с преподавателем возможна модификация схемы хранения, например хранение не исходной, а транспонированной матрицы. Дополнительное задание: реализовать функциональную спецификацию АТД Матрица. Индекс, равный нулю. означжзт отсутствие ненулевых элементов в строке (или в ее остатке). Если матрицы нс изменяются программой, возможна экономия памяти за счет отказа от хранения в массиве й индексов следующего элемента столбца (когда элементы идут подряд).

Вставка и удаление при этом способе возможны, но чересчур дороги: число перестановок элементов составит 0(Ж) вместо О(1). 2. Орю р: Ненулевому элементу соответствуют две ячейки: первая содержит номер столбца, вторая содержит значение элемента. Нуль в первой ячейке означает конец строки, а вторая ячейка содержит в этом случае номер следующей хранимой строки. Нули в обеих гщейках являются признаком конца перечня ненулевых элементов разреженной матрицы. Варианты преобразований: 4. 5.

б. 7. 10. 11. Вопросы для самостоятельного изучения к заданию ь>1П курсового проекта и к лабораторным работам № 23 и 24. 180/1ЕС 9899:1999 Ргойгагппггпй!апйпайея — С [С99! (для изучающих С! 1. 2. 3. 5. 1. 2 3. 5. 6. 7. 8. 9. 10. !!. 13. 14. 15. 16. 17. 18. 19. 20. 2!.

22. 23. 74 Определить максимальный по модулю элемент матрицы и разделить на него все элементы строки, в которой он находится. Если таких элементов несколько. обработать каждую строку, содержащую такой элемент. Определить максимальный по модулю элемент матрицы н рагделнть на него все элементы столбца, в котором он находится. Если таких элементов несколько, обработать предпоследний столбец, содержащий такой элемент.

Найти элемент матрицы. ближайший к заданному значению. Разделить на него элементы строки и столбца, на пересечении которых он расположен. Если таких элементов несколько, обработать все. Умножить разреженную матрицу на вектор-столбец и вычислить количество ненулевых элементов результата. Умножить вектор-строку на разреженную матрицу и вычислить количество ненулевых элементов ре.п льтата. Вычислить сумму двух разреженных матриц. Проверить, не является ли полученная матрица симметричной.

Найти строку, содеряшщую наибольшее количество ненулевых элементов, и напечатать ее номер и сумму элементов этой строки. Если таких строк несколько, обработать все. Вычислить произведение двух разракенных матриц. Проверить, не является зи полученная матрица диагональной. Найти столбец, содсрясащий наибольшее количество ненулевых элементов, и напечатать его номер и произведение элементов этого столбца. Если таких столбцов несколько обработать предпоследний. Вычислить матрочлен — многочлен первой степени от разрехсенной матрицы: (а М м Ь Е), где Š— единичная матрица, а и Ь вЂ” числовые константы. транспонировать разреженную матрицу относительно побочной диагонали.

Почему данная запись не работает?

#include <iostream>
using namespace std;

void foo(int *&pa){}

int main()
{
    int a[4]{};
    foo(a);
}

А когда я записываю так, то всё работает. В двух случаях же адрес указателя пытаюсь передать (значение указателя), т.е. сам указатель, в функцию, не создавая при этом новый, а просто ссылаясь на тот указатель. Имя массива может же служить указателем на его первый элемент, т.е. может хранить адрес первого элемента массива. Просто в первом случае я пропустил промежуточный указатель, т.к. имя массива тоже может служить им, но программа поломалась. Адрес то тот же передаю в функцию.

#include <iostream>
using namespace std;

void foo(int *&pa){}

int main()
{
    int a[4]{};
    int *x = a;
    foo(x);
}

Кстати, если создать динамический массив int *a = new int[4]; и потом передать a в функцию, то это тоже будет работать, что логично и работает адекватно.
Интересует именно c++.

Первый и второй принт выдадут разные результаты.

Массив размещается в стеке, там же размещается переменная name, где хранится адрес на первый элемент массива. В конец массива char компилятор добавляет символ с кодом 0x00 — признак конца строки. Именно по этому printf выводит правильное количество символов.

Первый принт выдаст адрес переменной name, а второй — содержимое (адрес символа ‘H’).

Третий же выведет все символы начиная с адреса, хранящегося в переменной name, пока не встретится 0x00.

sizeof выполняется на этапе компиляции, в машинном коде вместо него будут константы.
sizeof(name) вернёт размер указателя, а не размер массива, потому что вы определили не массив, а указатель, и присвоили ему адрес массива.

char name_array[] = "Hello World!"

Вот это уже массив, и sizeoff вернёт его размер, потому что он известен на этапе компиляции.

С указателями можно проводить арифметические операции. К примеру *(name+i) равносильно name[i].
К адресу прибавится не i, а i*sizeof(*name), т.е. размер типа указателя помноженный на число. Получаем i-ый элемент. Об этом позаботится компилятор. Для получения произвольного адреса необходимо привести указатель к типу void.

Массивы не являются указателями. Есть массивы, есть указатели. Есть адреса. Берём адрес массива и сохраняем его в указатель. В свою очередь указатель — это переменная, и она тоже располагается по какому-то адресу. Тут появляются указатели на указатели (иерархия не ограничена). К примеру многомерные массивы.

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

Учитывая глобальное объявление, подобное i; [не нужно было указывать тип, поскольку все было целым числом/указателем], обрабатывалось
компилятор как: address_of_i = next_global++; memory[address_of_i] = 0;, а инструкция типа i++ будет обрабатываться как: memory[address_of_i] = memory[address_of_i]+1;.

Объявление типа arr[10]; будет обрабатываться как address_of_arr = next_global; memory[next_global] = next_global; next_global += 10;. Обратите внимание, что как только эта декларация была обработана, компилятор мог сразу забыть о arr, являющемся массивом. Оператор типа arr[i]=6; будет обрабатываться как memory[memory[address_of_a] + memory[address_of_i]] = 6;. Компилятору все равно, будет ли arr представлять массив и i целое число, или наоборот. В самом деле, было бы все равно, являются ли они как массивами, так и целыми числами; он вполне с удовольствием генерирует код, как описано, без учета того, будет ли полученное поведение, вероятно, полезным.

Одна из целей языка программирования C была в значительной степени совместима с B. В B имя массива [называемого «вектором» в терминологии B] идентифицировало переменную, содержащую указатель, который был первоначально назначен чтобы указать на первый элемент распределения заданного размера, поэтому, если это имя появилось в списке аргументов для функции, функция получит указатель на вектор. Несмотря на то, что C добавил «реальные» типы массивов, имя которых было жестко связано с адресом распределения, а не с переменной указателя, которая первоначально указывала бы на распределение, имея массивы, разлагающиеся на код, созданный указателями, который объявлял массив C-типа одинаковым к коду B, который объявил вектор, а затем никогда не изменял переменную, содержащую ее адрес.

Сколько ошибок в таком маленьком коде…

#include <iostream>

а дальше весь код на чистом си. Какой смысл — никакого. Добавляем

#include <stdio.h>

и пишем все на чистом си.

setlocale(LC_ALL, "rus");

это исключительно для старых систем. На нормальных OS это не нужно.

float b[100][100];

запомним — двумерный массив вещественных чисел.

scanf("%d", b+i+j);

а здесь сходу сразу минимум две ошибки (а то и все три).

Первое — раз сказали, что массив вещественных чисел, почему вводим целое? scanf наивный и вводит так как сказали. Какой будет результат — неведомо.

Второе — адресация массива. Так как массив размером 100 на 100, то индексы девяти элементов должны быть 0,1,2,100,101,102,200,201,202. А по этой формуле выходит 0, 4, 8, 4, 8, 12, 8, 12, 16. Но я сознательно сделал умолчал об одном. В первом случае это индексы в массиве. А массив имеет тип вещественного (у Вас). А это скорее всего 4 (а может и 6 или 8) байт. А во втором случае это просто адреса. Переформулирую. Если привести все к адресам в байтах, то для массива целых 4 байтовых адреса будут такими:

0, 4, 8, 400, 404, 408, 800, 804, 808

Поэтому, так как вводим непонятно что, то и вывод обсуждать не имеет смысла.

Итак, мой вариант

#include <stdio.h>

void main() {
    int i, j,
        n = 3, // строки
        m = 3; // столбцы
    int b[100][100];

    // Создаем матрицу
    for (i=0;i<n;i++) {
        for (j=0;j<m;j++) {
            printf("Введите элемент [%i,%i]: ", i+1, j+1);
            scanf("%d", &b[i][j]); //явная, нормальная адресация
        }
        printf("n");
    }

    // Выводим матрицу
    printf("----------------------------n");
    for (i=0;i<n;i++) {
        for (j=0;j<m;j++) {
            printf("%dt", b[i][j]); // 1
        }
        printf("n");
    }
    printf("----------------------------n");
}

О динамических массивах в языке Си: что это такое, виды, как с ними работать

Содержание:

  • Что такое динамический массив

    • Указатели для динамических массивов
    • Ошибки, возникающие при неверном использовании динамических массивов
  • Виды динамических массивов
  • Стандартные функции динамического выделения памяти
  • Выделение памяти под двумерный массив
  • Нестандартные функции динамического выделения памяти
  • Перераспределение памяти

Что такое динамический массив

Определение

Массив — последовательная группа ячеек памяти, имеющих одинаковое имя и одинаковый тип. То есть это структуры, которые содержат связанные друг с другом однотипные элементы данных.

Они занимают область в памяти. Компилятор резервирует соответствующий объем памяти для каждого типа и количества элементов каждого массива.

Чтобы зарезервировать память при помощи компилятора для статического массива, необходимо указать ему сколько в нем будет элементов целых чисел. Для этого используется объявление int a [] ;

Осторожно! Если преподаватель обнаружит плагиат в работе, не избежать крупных проблем (вплоть до отчисления). Если нет возможности написать самому, закажите тут.

Пример

Пример объявления для 12 элементов:

int a [12] ;

Для динамического массива количество элементов не указывают.

На этапе написания программы размер динамических массивов неизвестен. Ввод количества элементов осуществляется во время работы программы.

Размером при объявлении динамического массива является числовая переменная, а не константа.

Передача динамических массивов в функцию осуществляют через указание на начало массива указателей. То есть объявляют тип указателя, содержащего данные об адресе соответствующего первого элемента массива.

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

Указатели для динамических массивов

Одним из основных понятий языка Си являются указатели. Они представляют собой переменные, хранящие информацию об адресе какого-либо объекта. Их особенностью является то, что иногда только с их помощью можно выполнить некоторые операции, или записать код более компактно и эффективно, чем при использовании других способов.

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

Действия с указателями

  1. Объявление.

Указатели:

  • int *pI;
  • char *pC;
  • float *pF;

Чтобы объявить указатель, объявляют тип переменной и ставят перед именем символ *. Указанная переменная должна быть одного типа с указателем, который на ее указывает.

  1. Присвоение адреса.

Указатели:

  • pI = &i;
  • int i, *pI;

Адрес присваивается указателю с помощью оператора &. Знак &, стоящий перед переменной, будет указывать на ее адрес.

  1. Получение значения по этому адресу.

Указатели:

  • f = *pF;
  • float f, *pF;

Для переменной определенного типа, на которую определен указатель, например, pF, указывается число соответствующего типа. Символ * перед pF означает информацию ячейки, указанной pF.

  1. Сдвижение.

Указатели:

  • int *pI;
  • pI ++;
  • pI -= 4;
  • pI += 4;

Подобные операции позволяют сдвигать значение указателя на то или иное целое число или количество байтов.

  1. Обнуление.

Указатели:

  • char *pC;
  • pC = NULL;

Указатель указывает на недействительный адрес, который равен нулю, соответственно, указатель тоже недействительный. Запись по нему не может быть осуществлена.

  1. Выведение на экран.

Указатели:

  • int i, *pI;
  • printf(«Адр.i =%p», pI);
  • pI = &i;

Для вывода указателей на экран применяют формат %p.

Ошибки, возникающие при неверном использовании динамических массивов

  1. Запись в чужую область памяти.

Причина: Выделение памяти произошло неудачно, при этом массив используется.

Вывод: необходимо всегда осуществлять проверку указателя на NULL. Если значение указателя будет равно нулю при проверке после выделения памяти, то использование такого массива будет приводить к зависанию компьютера.

  1. Повторное удаление указателя.

Причина: Массив уже удален и теперь удаляется снова.

Вывод: если массив удален из памяти, необходимо обнулить показатель, так можно быстрее выявить ошибку.

  1. Выход за границы массива

Причина: В массив записан элемент с отрицательным индексом или индексом, выходящим за границу массива.

  1. Утечка памяти

Причина: Неиспользуемая память не освобождается. Если это происходит в функции, которая вызывается много раз, то ресурсы памяти скоро будут израсходованы. Вывод: необходимо тщательно проверить код, и удалить артефакты.

Виды динамических массивов

Классификация динамических массивов:

  • одномерные: int * A;
  • двумерные: int ** A;

Одномерный динамический массив представляет собой множество элементов одного типа данных.

Двухмерный массив имеет более сложную структуру и содержит в качестве элементов массива другие массивы. Каждому хранящемуся в массиве А указателю присвоено не одно значение, а одномерный динамический массив таких значений.

Переменная А сама является указателем и объявляется как указатель на указатель на нужный тип. Данный указатель нужно инициализировать, то есть положить ему адрес массива адресов. В памяти программы должен существовать массив адресов указателей на int и сам массив указателей на int. В этом массиве указателей должны быть разложены адреса, возможно лежащие отдельно друг от друга в памяти.

Пример двумерного массива:

  1. #include <iostream> // здесь указывают заголовок файла, содержащего функции, переменные, классы, для организации операций ввода-вывода
  2. using namespace std; // объявление пространства имен для ограничения видимости переменных, функций и т.д.
  3. int main() {
  4. setlocale(0, «»); “// указывают тип значения, возвращаемого функцией, и задают локаль для программы
  5. int **dinamic_array2 = new int* [5];
  6. for (int i = 0; i < 5; i++) {
  7. dinamic_array2[i] = new int [i + 1];
  8. } // Создание двумерного массива
  9. for (int i = 0; i < 5; i++) {
  10. cout << «Введите числа» << «(» << i + 1 << «)» << «:»;
  11. for (int j = 0; j < i + 1; j++) {
  12. cin >> dinamic_array2[i][j];
  13. }
  14. } // заполнение массива
  15. for (int j = 0; j < i + 1; j++) {
  16. sum += dinamic_array2[i][j];
  17. }
  18. cout << «Сумма » << i + 1 << » массива равна » << sum << endl;
  19. } // проведение различных операций по вводу-выводу
  20. for (int i = 0; i < 5; i++) {
  21. delete [] dinamic_array2[i]; // удаление массива
  22. }
  23. system(«pause»);
  24. return 0;
  25. }

Строки 5-8 — создание динамического массива.

Строки 9-14 — заполнение.

Строки 15-19 — подсчет, сортировка и вывод на экран суммы всех массивов.

Строки 20-22 — удаление массива.

Стандартные функции динамического выделения памяти

В языке программирования Си имеются стандартные функции управления памятью:

  1. Malloc (от англ. memory allocation, выделение памяти). Функция malloc возвращает указатель на n байт неинициализированной памяти или NULL, если запрос на память нельзя выполнить: void *malloc(size_t n). Значение, которое возвращает malloc, — это адрес начала выделенной области памяти. При этом гарантируется соответствующее выравнивание этого адреса на границу памяти, обеспечивающую хранение в области любого объекта.
  2. Calloc (от англ. clear allocation, чистое выделение памяти). Функция calloc возвращает указатель на участок памяти, достаточный для размещения п объектов заданного размера size или NULL, если запрос на память невыполним. Память инициализируется нулями; void *calloc(size_t n, size_t size).
  3. Realloc (от англ. reallocation, перераспределение памяти). Используется для изменения величины выделенной памяти, на которую указывает ptr, на новую величину, задаваемую параметром newsize. Эта функция может перемещать блок памяти на новое место, в этом случае функция возвращает указатель на новое место в памяти.
  4. Free (англ. free, освободить). Функция free(p) освобождает участок памяти, на который указывает указатель р, первоначально полученный вызовом функции malloc или calloc. Порядок освобождения выделенных участков памяти не регламентируется. Однако если указатель не был получен с помощью malloc или calloc, то его освобождение является грубой ошибкой. Обращение по указателю после его освобождения — также ошибка. Правильным было бы записать все, что нужно, перед освобождением:

for (p = head; p != NULL; p = q) {

q = p->next;

free(p);

}

Выделение памяти под двумерный массив

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

Например, есть указатель А: int ** A ;

Сначала создают массив, состоящий из указателей, которые будут отвечать количеству строк:

A = (int **) malloc (N * sizeof(int *)). Здесь важно указать тип указателя, а не int. Потому что в этом массиве, на который указывает A, будут храниться указатели, а не int.

Далее инициализируют уже сами элементы этого массива указателей путем запуска цикла:

for (int i = 0 ; i < N ; ++i).

Для каждого A[i] проводим инициализацию по отдельности. По сути этого разыменование А со смещением i:

A[i] = (int *) malloc (M * sizeof (int)). Указатели A[i] уже указывают на массив int. Если бы был другой тип, то указывали бы на него.

Для освобождения памяти используют схему: сначала освобождают память для указателей, а потом уже для самого указателя A. То есть массив, который выделил массив указателей, тоже сбрасывают.

int ** A ;

A = (int **) malloc (N * sizeof(int *)).

for (int i = 0 ; i < N ; ++i).

free (A[i]) ;

free (A) ;

Нестандартные функции динамического выделения памяти

Когда требуемый размер массива становится известен, то используют оператор new из языка Си ++, который является расширенной версией языка Си. В скобках указывают размер массива:

pI =new int [N] ;

При отрицательном или нулевом N использовать оператор new нельзя.

При динамическом распределении памяти основными операциями являются new и delete.

Операция new принимает в качестве аргумента тип динамически размещаемого объекта и возвращает на него указатель.

Например, оператор Node *newPtr = new NodeA0); используется для выделения области памяти размером sizeof(Node) байтов, а также его применяют для сохранения указателя на данной области памяти в указателе newPtr.

Если планируется использовать память повторно, после того, как динамический массив в какой-то момент работы программы перестанет быть нужным, то ее освобождают с помощью delete[],

При этом не указывают размерность массива. Операция delete освобождает область памяти, выделенную при помощи оператора new. Таким образом, она возвращает системе эту область памяти для дальнейшего распределения. Чтобы освободить память, которая была динамически выделена предыдущим оператором, применяют оператор delete newPtr;

Иногда выделение памяти под динамические массивы осуществляют с помощью двух языков Си и Си++ одновременно: операции new и функции malloc.

Пример

int n = 10;

int *a = new int[n];

double *b = (double *)malloc(n * sizeof (double));

Во второй строке описан указатель на целую величину. Ему присвоен адрес начала непрерывной области динамической памяти, выделенной с помощью операции new. В зависимости от того, сколько присутствует n величин типа int, столько выделяется памяти для их хранения. Величина n может являться переменной.

В третьей строке применяется функция malloc, которая в данном случае выделяет память под n элементов типа double. Для того, чтобы освободить память, выделенную с помощью функции malloc, применяют функцию free. Память не обнуляется при ее выделении. Динамический массив нельзя инициировать.

Перераспределение памяти

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

Объем доступной физической памяти или доступной виртуальной памяти в системах с виртуальной памятью определяют пределы динамического выделения памяти. При делении свободной памяти при совместном доступе между многими пользователями эти пределы несколько снижены.

Функция realloc осуществляет перераспределение памяти. Она меняет размер динамически выделяемой области памяти, адресуемой указателем ptr, на новый размер size.

Realloc может возвращать адрес новой области памяти:

realloc(void *ptr, size_t size);

Если ptr равен NULL, то realloc ведет себя подобно функции malloc.

Поведение функции realloc будет неопределенным, если:

  • значение ptr не было возвращено функциями calloc, malloc или realloc;
  • пространство памяти было освобождено функцией free, и ptr указывают на него.

Size указывают в абсолютном значении.

Важные моменты в перераспределении памяти с помощью функции realloc:

  1. Если существующее пространство меньше по размеру, чем size, то в конце будет выделяться новое неинициализированное непрерывное пространство, при этом предыдущие данные пространства будут сохранены.
  2. Значение, равное NULL, будет возвращено, если realloc не может выделить запрашиваемое пространство, а в указанном ptr пространстве содержимое остается нетронутым.
  3. Realloc будет действовать, как функция free, если size=0, а ptr не равен NULL.
  4. Если первым параметром функции realloc использовать NULL, то можно получить эффект, который достигается с помощью функции malloc с тем же значением size.

Новое пространство может начинаться с отличного от заданного адреса, независимо от того, в какой момент функция realloc изменяла пространство, даже если она усекала память. Поэтому указатели могут адресоваться к перемещаемому пространству, что необходимо учитывать при разработке программы.

Например, при создании связанного списка linked list и применения realloc, чтобы выделить для цепочки пространство памяти, может оказаться, что оно будет перемещаться. В таком случае, указатели будут адресованы не в место их расположения в настоящий момент, а в то место, где были размещены последовательные звенья цепочки.

Пример

Пример использования функции realloc:

p2 = realloc(p1, new_size);

if (p2 1= NULL) p1 = p2;

Необходимо учитывать, что realloc работает с ранее выделенной памятью и старыми строками. Добавление новых строк и выделение памяти осуществляется посредством функций calloc или malloc.

Понравилась статья? Поделить с друзьями:
  • Ошибки адольфа гитлера
  • Ошибки администратора салона красоты
  • Ошибки администратора гостиницы
  • Ошибки адверс пжд
  • Ошибки адаптивного дизайна