S
S
sudo rm -rf /2017-10-12 17:18:00
API
sudo rm -rf /, 2017-10-12 17:18:00

Weird winAPI memory access error. How to decide?

I wanted to write a program for drawing the Sperinsky triangle.

  • double* lineFrom(HDC hDC, double x, double y, double l, double angle) - draws a line of length a , from point (x,y) , at angle angle ; returns the coordinates of the new point
  • double* triangle(HDC hDC, double x, double y, double a, double angle = 0) - draws an equilateral triangle with side a , from point (x,y) - vertex rotated by angle angle ; returns the coordinates of the other two vertices {x1, y1, x2, y,2}
  • void cut(HDC hDC, double* PT, double a, size_t n, double angle = 0) - "cuts" (draws a smaller triangle) an equilateral triangle with side a/2 , from a triangle with two vertices PT rotated by angle angle

I wrote a recursive version, but I didn’t like that with a large N, you have to wait a long time for rendering.
The code. recursion
#include <windows.h>
#include <conio.h>
#define _USE_MATH_DEFINES
#include <cmath>

#define GREEN RGB(138, 179, 45)
#define   RED RGB(181,2,51)

/*Settings*/
#define  DELY 0
#define     N 14
#define   LEN 900
#define   AGL 0
#define COLOR GREEN

double* lineFrom(HDC hDC, double x, double y, double l, double angle) {
  Sleep(DELY);
  double dX = l*cos(angle), dY = l*sin(angle);
  double* res = new double[2];
  res[0] = x + dX;
  res[1] = y + dY;
  MoveToEx(hDC, x, y, NULL);
  LineTo(hDC, res[0], res[1]);
  return res;
}

double getRad(double grad) {
  return (grad / 180) * M_PI;
}

double middle(double a, double b) {
  return (a - b) / 2 + b;
}

double* triangle(HDC hDC, double x, double  y, double a, double angle = 0) {
  double* buff = new double[2];
  double* bPoint = new double[4];
  buff[0] = x; buff[1] = y;
  angle += getRad(60);
  buff = lineFrom(hDC, buff[0], buff[1], a, angle);
  bPoint[0] = buff[0]; bPoint[1] = buff[1];
  buff = lineFrom(hDC, buff[0], buff[1], a, angle += getRad(120));
  bPoint[2] = buff[0]; bPoint[3] = buff[1];
  buff = lineFrom(hDC, buff[0], buff[1], a, angle += getRad(120));
  return bPoint;
}

double geth(double a) {
  return  a * sqrt(3) / 2;
}

void cut(HDC hDC, double* PT, double a, size_t n, double angle = 0) {
  double* D = new double[2];
  a /= 0;
  D[0] = middle(PT[0], PT[2]);
  D[1] = middle(PT[1], PT[3]);
  double* sP = triangle(hDC, D[0], D[1], a, angle - getRad(180));
  n -= 1;
  if (n > 0) {
    double* sp2 = new double[4];
    cut(hDC, sP, a, n, angle);

    sp2[0] = D[0]; sp2[1] = D[1];
    sp2[2] = PT[2]; sp2[3] = PT[3];
    cut(hDC, sp2, a, n, angle);

    sp2[0] = PT[0]; sp2[1] = PT[1];
    sp2[2] = D[0]; sp2[3] = D[1];
    cut(hDC, sp2, a, n, angle);
  }
}

void main() {
  HWND hwnd;
  char Title[1024];
  GetConsoleTitle(Title, 1024);
  hwnd = FindWindow(NULL, Title);
  RECT rc;
  GetClientRect(hwnd, &rc);
  int iWidth = rc.right;
  int iHeight = rc.bottom;
  HDC hdc = GetDC(hwnd);
  HPEN p1, p2 = CreatePen(PS_SOLID, 2, COLOR);
  p1 = (HPEN)SelectObject(hdc, p2);

  double curX, curY;
  curX = (iWidth) / 2;
  curY = (iHeight - geth(LEN)) / 2;

  double* bPoint = triangle(hdc, curX, curY, LEN, getRad(AGL));
  cut(hdc, bPoint, LEN, N, getRad(AGL));


  SelectObject(hdc, p1);
  ReleaseDC(hwnd, hdc);
  DeleteObject(p2);
  _getch();
}

I decided to redo it for the sake of interest through iterations. (I only changed void cut()) It's clear that it needs more memory, because for each next iteration, 4*3^i double variables are required to store data for iteration.
Everything seems to be fine, but when i = 4, the winApi lineTo function gives a memory access error. What could be the problem? Changed only cut. Worked for any N.
The code. Iterations
#include <windows.h>
#include <conio.h>
#define _USE_MATH_DEFINES
#include <cmath>

#define GREEN RGB(138, 179, 45)
#define   RED RGB(181,2,51)

/*Settings*/
#define  DELY 0
#define     N 4
#define   LEN 900
#define   AGL 0
#define COLOR GREEN



double getRad(double grad) {
  return (grad / 180) * M_PI;
}

double middle(double a, double b) {
  return (a - b) / 2 + b;
}

double geth(double a) {
  return  a * sqrt(3) / 2;
}

double* lineFrom(HDC hDC, double x, double y, double l, double angle) {
  Sleep(DELY);
  double dX = l*cos(angle), dY = l*sin(angle);
  double* res = new double[2];
  res[0] = x + dX;
  res[1] = y + dY;
  MoveToEx(hDC, x, y, NULL);
  LineTo(hDC, res[0], res[1]);
  return res;
}

double* triangle(HDC hDC, double x, double  y, double a, double angle = 0) {
  double* buff = new double[2];
  double* bPoint = new double[4];
  buff[0] = x; buff[1] = y;
  angle += getRad(60);
  buff = lineFrom(hDC, buff[0], buff[1], a, angle);
  bPoint[0] = buff[0]; bPoint[1] = buff[1];
  buff = lineFrom(hDC, buff[0], buff[1], a, angle += getRad(120));
  bPoint[2] = buff[0]; bPoint[3] = buff[1];
  buff = lineFrom(hDC, buff[0], buff[1], a, angle += getRad(120));
  return bPoint;
}

void cut(HDC hDC, double* PT, double a, size_t n, double angle = 0) {
  /* Создание массива A для аргументов размером [1][4] */
  double **A, **B;
  A = new double*[1];
  A[0] = new double[4];
  
  /* Инициализация A начальными значениями */
  A[0][0] = PT[0]; A[0][1] = PT[1];
  A[0][2] = PT[2]; A[0][3] = PT[3];

  for (int i = 0; i < n; ++i) {
    B = new double*[(i+1) * 3];
    a /= 2;
    for (int j = 0; j < pow(3, i); ++j) {
      /* Буффер данных для след. итерации*/
      for(int k = 0; k < 3; ++k)
        B[3 * j + k] = new double[4]; // Нужно ли создавать или достаточно присвоить?

        
      /* Обрезаем для текущего */
      double D[2] = { 
        middle(A[j][0], A[j][2]), 
        middle(A[j][1], A[j][3])
      };
      double* buff = triangle(hDC, D[0], D[1], a, angle - getRad(180));
  
      /* Расчет параметров для j+1 и запись их в В*/
      B[3 * j + 0][0] = buff[0]; B[3 * j + 0][1] = buff[1];
      B[3 * j + 0][2] = buff[2]; B[3 * j + 0][3] = buff[3];

      B[3 * j + 1][0] = D[0];    B[3 * j + 1][1] = D[1];
      B[3 * j + 1][2] = A[j][0]; B[3 * j + 1][3] = A[j][1];

      B[3 * j + 2][0] = A[j][2]; B[3 * j + 2][1] = A[j][3];
      B[3 * j + 2][2] = D[0];    B[3 * j + 2][3] = D[1];
      
      delete[] A[j];
    }
    delete[] A; // Нужно ли удалять или достаточно приравнять?
  }
}

void main() {
  HWND hwnd;
  char Title[1024];
  GetConsoleTitle(Title, 1024);
  hwnd = FindWindow(NULL, Title);
  RECT rc;
  GetClientRect(hwnd, &rc);
  int iWidth = rc.right;
  int iHeight = rc.bottom;
  HDC hdc = GetDC(hwnd);
  HPEN p1, p2 = CreatePen(PS_SOLID, 2, COLOR);
  p1 = (HPEN)SelectObject(hdc, p2);

  double curX, curY;
  curX = (iWidth) / 2;
  curY = (iHeight - geth(LEN)) / 2;

  double* bPoint = triangle(hdc, curX, curY, LEN, getRad(AGL));
  cut(hdc, bPoint, LEN, N, getRad(AGL));

  SelectObject(hdc, p1);
  ReleaseDC(hwnd, hdc);
  DeleteObject(p2);
  _getch();
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
R
res2001, 2017-10-12
@MaxLevs

1. FOR EACH NEW OPERATION, THERE SHOULD BE A CORRESPONDING DELETE OPERATION.
You are clearly missing delete in different places.
2. Use two-dimensional arrays as you use them ... well, this is some kind of perversion. Is that how they teach now? I understand that it is convenient to do [i][j] ... but there is also address arithmetic, denaming. And you can easily go from a pointer to a two-dimensional array, to a pointer to a one-dimensional and use indexing on a one-dimensional array.
3. No need to allocate memory at each iteration of the loop - it is enough to allocate an array of the maximum size at the very beginning, and then use it inside the loop at all iterations.
4.Usually, just recursion is more gluttonous to memory (and to the CPU) than the iterative method, because recursion eats up the stack and if there is a large nesting, then the stack may end.
PS: about the memory error: run the program under the debugger, it will break when an error occurs, in the debugger you can go to your last function (along the call stack) and see where something is wrong (I hope you don't think that the error is really in lineTo ).

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question