• Two-dimensional dynamic array. One-dimensional dynamic arrays

    // declaration of a two-dimensional dynamic array of 10 elements:

    float **ptrarray = new float* ; // two lines in the array

    for (int count = 0; count< 2; count++)

    ptrarray = new float ; // and five columns

    // where ptrarray is an array of pointers to the allocated memory area for the array real numbers float type

    First, a second-order pointer float **ptrarray is declared, which refers to an array of float* pointers, where the size of the array is two . After which, in the for loop, each line of the array declared in line 2 memory is allocated for five elements. The result is a two-dimensional dynamic array ptrarray. Let's consider an example of freeing memory allocated for a two-dimensional dynamic array.

    // freeing memory allocated for a two-dimensional dynamic array:

    for (int count = 0; count< 2; count++)

    delete ptrarray;

    // where 2 is the number of lines in the array

    #include
    #include
    #include
    void main()
    {

    int *a; // pointer to array

    system("chcp 1251");

    scanf("%d", &n);

    scanf("%d", &m);

    // Memory allocation

    a = (int*) malloc(n*m*sizeof(int));

    // Entering array elements

    for(i=0; i

    for(j=0; j

    printf("a[%d][%d] = ", i, j);

    scanf("%d", (a+i*m+j));

    // Output array elements

    for(i=0; i

    for(j=0; j

    printf("%5d ", *(a+i*m+j)); // 5 acquaintances for an array element

    getchar(); getchar();
    }

    Execution result

    Enter number of lines: 3

    Enter number of columns: 4

    Another way to dynamically allocate memory for a two-dimensional array is also possible - using an array of pointers. To do this you need:
    - allocate a block of RAM for an array of pointers;
    - allocate blocks of RAM for one-dimensional arrays, which are rows of the desired matrix;
    - write the addresses of the lines into an array of pointers.

    The malloc() function returns a pointer to the first byte of a memory area of ​​size size that was allocated from a dynamically allocated memory area. If there is not enough memory in the dynamic memory area, a null pointer is returned.

    #include
    #include
    #include
    void main()
    {

    int**a; // pointer to pointer to string

    system("chcp 1251");

    printf("Enter the number of lines: ");

    scanf("%d", &n);

    printf("Enter the number of columns: ");

    scanf("%d", &m);

    // Allocating memory for pointers to strings

    a = (int**)malloc(n*sizeof(int*));

    // Entering array elements

    for(i=0; i

    // Allocating memory for storing strings

    a[i] = (int*)malloc(m*sizeof(int));

    for(j=0; j

    printf("a[%d][%d] = ", i, j);

    scanf("%d", &a[i][j]);

    // Output array elements

    for(i=0; i

    for(j=0; j

    printf("%5d ", a[i][j]); // 5 acquaintances for an array element

    free(a[i]); // freeing memory for the string

    getchar(); getchar();
    }

    The result of executing the program is similar to the previous case.

    Using dynamic memory allocation for row pointers, you can allocate free arrays. Free is a two-dimensional array (matrix), the size of the rows of which can be different. The advantage of using a free array is that you don't have to allocate too much computer memory to accommodate a string of the maximum possible length. In fact, a free array is a one-dimensional array of pointers to one-dimensional data arrays.

    Pointers.

    A pointer is a variable whose value is the address at which the data is located. An address is the number of the memory cell in or from which the data is located.

    According to data type in SI, pointers are divided into:

    A typed pointer is a pointer containing the address of data of a certain type (system or user).

    An untyped pointer is a pointer containing a data address of an unspecified type (just an address).

    Pointer declaration;

    Setting the pointer;

    accessing a value located at a pointer. The declaration (description) of a pointer in the SI language has the following form:

    Type *name [=value];

    When declared, a pointer in SI can be initialized by indicating the corresponding value through an assignment sign. This value must be an address, written in one of the following forms:

    Null (id NULL);

    Another pointer;

    Variable address (through the operation of taking the address);

    An expression that represents pointer arithmetic;

    The address that is the result of a dynamic memory allocation.

    #include

    int var; // regular integer variable

    int *ptrVar; // integer pointer (ptrVar must be of type int, since it will refer to a variable of type int)

    ptrVar = // assigned the pointer the address of the memory cell where the value of the var variable lies

    scanf("%d", &var); // the variable var contains the value entered from the keyboard

    printf("%d\n", *ptrVar); // output value via pointer

    Execution result: 6 6

    Lecture No. 3.

    Functions.

    A function is a syntactically identified named program module that performs a specific action or group of actions. Each function has its own interface and implementation. Function interface – function header, which indicates the name of the function, a list of its parameters and the type of the return value.

    The description of a function in SI language is carried out anywhere in the program outside the description of other functions and consists of three elements:

    1. function prototype;

    2. function header;

    3. function body.

    A function prototype is an optional part of a function description, intended to declare a function whose interface corresponds to a given prototype. The prototype declaration has the following form:

    Type name(list of formal parameter types);

    Function parameters are values ​​passed to the function when it is called.

    Function header is a description of the interface part of the function, which contains: the return value type, the name of the function and a list of formal parameters of the function. The syntax for declaring a function header is:

    Type name(list of formal parameters)

    Examples of function headers:

    Int func(int i, double x, double y)

    Void func(int ind, char *string)

    Double func(void)

    The body of a function is the implementation part containing the program code that is executed when the function is called. The function body always comes immediately after the function head (they cannot be separated) and is enclosed in curly braces.

    Implementation of a function in SI to calculate the factorial of a number.

    Double factorial(unsigned);

    Double factorial(unsigned num)

    Double fact = 1.0;

    For(unsigned i=1;i<=num;i++)

    Fact *= (double)i;

    Return fact;

    Structures.

    A structure is a complex data type that represents a set of elements of various types ordered in memory. Each element in the structure has its own name and is called a field.

    The declaration in SI of a structure looks like:

    Struct [type name]

    Field_1;

    Field_2;

    Field_N;

       ) [list of variables];

    Declaration of structure fields is possible only without initialization. If several fields following each other in the structure description have the same type, then to describe them you can use the syntax for declaring several variables of the same type.

    Files.

    A file is a named area of ​​data on some storage medium. File types (relative to SI language):
       text;
       binary.
    Basic operations performed on files:
    1.Opening files.
    2.Reading and writing data.
    3.Closing files.

    Additional operations:
    1.File navigation.
    2. Handling errors when working with files.
    3.Deleting and renaming files.
    4.Description of the variable

    Opening modes files with SI

    Stream redirection
      FILE * freopen(const char *filename, const char *mode, FILE *stream);

    The function returns:
      Pointer to file - everything is fine,
      NULL – override error.

    Closing a file
      int fclose(FILE *stream);

    The function returns:
      0 – file closed successfully.
      1 – an error occurred in closing the file.

    End of file check
      int feof(FILE *stream);
      stream - pointer to an open file.

    The function returns:
      0 – if the end of the file has not yet been reached.
      !0 – end of file reached.

    Opening text files
    The second parameter additionally specifies the character t (optional):
      rt, wt, at, rt+, wt+, at+

    Reading from a text file

    Formatted Reading
      int fscanf(FILE *stream, const char * format, ...);

    The function returns:
      >0 – number of successfully read variables,
      0 – none of the variables were successfully read,
      EOF – error or end of file reached.
    Reading a line

    The function returns:
      buffer - everything is fine,
    Reading a line
      char * fgets(char * buffer, int maxlen, FILE *stream);

    The function returns:
      buffer - everything is fine,
      NULL – error or end of file reached.
    Reading a symbol
      int fgetc(FILE *stream);
    The function returns:
      symbol code - if everything is fine,
      EOF – if an error occurred or the end of the file was reached.
    Putting a character back into the stream
      int ungetc(int c, FILE *stream);
    The function returns:
      symbol code – if everything is successful,
      EOF – an error occurred.

    Write to text SI file

    Formatted output
      int fprintf(FILE *stream, const char *format, ...);
    The function returns:
      number of characters written - if everything is normal,
      negative value – if there is an error.
    Writing a string
      int fputs(const char *string, FILE *stream);
    The function returns:
      number of characters written - everything is fine,
      EOF – an error occurred.
    Write a symbol
      int fputc(int c, FILE *stream);
    The function returns:
      code of the recorded symbol - everything is fine,
      EOF – an error occurred.
    Opening binary files
      The second parameter additionally specifies the character b (required): rb, wb, ab, rb+, wb+, ab+
    Reading from binary files
      size_t fread(void *buffer, size_t size, size_t num,FILE *stream);
    The function returns the number of blocks read. If it is less than num, then an error occurred or reached
    end of file.

    Writing to a binary file
      size_t fwrite(const void *buffer, size_t size, size_t num, FILE *stream);
    The function returns the number of blocks written. If it is less than num, then an error occurred.

    File navigation

    Reading the current offset in a file:
      long int ftell(FILE *stream);
    Changing the current offset in a file:
      int fseek(FILE *stream, long int offset, int origin);

    SEEK_SET (0) – from the beginning of the file.
      SEEK_CUR (1) – from the current position.
      SEEK_END (2) – from the end of the file.
    The function returns:
      0 – everything is fine,
      !0 – an error occurred.
    Move to the beginning of the file:
      void rewind(FILE *stream);
    Reading the current position in a file:
      int fgetpos(FILE *stream, fpos_t *pos);
    Setting the current position in the file:
      int fsetpos(FILE *stream, const fpos_t *pos);
    The functions return:
      0 – everything is successful,
      !0 – an error occurred.
    fpos_t structure:
      typedef struct fpos_t (
       long off;
       mbstate_t wstate;
      ) fpos_t;

    Getting an error sign:
      int ferror(FILE *stream);
    The function returns a non-zero value if an error occurs.
    Error reset function:
      void clearerr(FILE *stream);
    Error message function:
      void perror(const char *string);

    Buffering

    Buffer clear function:
      int fflush(FILE *stream);
    The function returns:
      0 – everything is fine.
      EOF – an error occurred.
    Buffer management function:
      void setbuf(FILE *stream, char * buffer);

    Creates a buffer of size BUFSIZ. Used before input or output to the stream.

    Temporary files

    Temporary file creation function:
      FILE * tmpfile(void);
    Creates a temporary file in wb+ mode. After closing the file, the latter is automatically deleted.
    Temporary file name generation function:
      char * tmpnam(char *buffer);

    Deleting and renaming

    File Delete Function:
      int remove(const char *filename);
    File rename function:
      int rename(const char *fname, const char *nname);
    The functions return:
      0 – if successful,
      !0 – otherwise.

    Lecture No. 4.

    Stack.

    A stack is the opposite of a queue because it operates on a last-in, first-out (LIFO) basis. To visualize a stack, think of a stack of plates. The first plate placed on the table will be used last, and the last plate placed on top will be used first. Stacks are often used in system software, including compilers and interpreters.

    When working with stacks, the operations of inserting and retrieving an element are the main ones. These operations are traditionally called “push” and “pop”. Therefore, to implement a stack, you need to write two functions: push(), which “pushes” a value onto the stack, and pop(), which “pops” a value from the stack. You also need to allocate an area of ​​memory that will be used as a stack. For this purpose, you can allocate an array or dynamically allocate a piece of memory using the C language functions provided for dynamic memory allocation. As with a queue, the fetch function takes an element from the list and removes it if it is not already stored elsewhere. Below is the general form of the push() and pop() functions that operate on an integer array. Other types of data stacks can be organized by changing the underlying data type of the array.

    int tos=0; /* top of stack */

    /* Push an element onto the stack. */

    void push(int i)

    if(tos >= MAX) (

    printf("Stack is full\n");

    /* Get the top element of the stack. */

    if(tos< 0) {

    printf("Stack is empty\n");

    return stack;

    The tos variable ("top of stack") contains the index of the top of the stack. When implementing these functions, it is necessary to take into account cases when the stack is full or empty. In our case, the sign of an empty stack is that tos is equal to zero, and the sign of a stack overflow is that tos increases so much that its value points somewhere beyond the last cell of the array.

    An example of working with a stack.

    The stack will be located in dynamically allocated memory, and not in a fixed-size array. Although using dynamic memory allocation is not necessary in such a simple example, we will see how to use dynamic memory to store stack data.

    /* A simple calculator with four steps. */

    #include

    #include

    int *p; /* pointer to free memory area */

    int *tos; /* pointer to the top of the stack */

    int *bos; /* pointer to the bottom of the stack */

    void push(int i);

    p = (int *) malloc(MAX*sizeof(int)); /* get memory for stack */

    printf("Error while allocating memory\n");

    bos = p + MAX-1;

    printf("Four step calculator\n");

    printf("Press "q" to exit\n");

    printf("%d\n", a+b);

    printf("%d\n", b-a);

    printf("%d\n", b*a);

    printf("Divide by 0.\n");

    printf("%d\n", b/a);

    case ".": /* show the contents of the top of the stack */

    printf("Current value at the top of the stack: %d\n", a);

    ) while(*s != "q");

    /* Pushing an element onto the stack. */

    void push(int i)

    if(p > bos) (

    printf("Stack is full\n");

    /* Get the top element from the stack. */

    if(p< tos) {

    printf("Stack is empty\n");

    Queue.

    A queue is a linear list of information that is processed on a first-in, first-out basis; this principle (and the queue as a data structure) is sometimes also called FIFO. This means that the first element placed in the queue will be received from it first, the second element placed will be removed second, etc. This is the only way to work with a queue; random access to individual elements is not permitted.

    To imagine how the queue works, let's introduce two functions: qstore() and qretrieve() (from "store" - "save", "retrieve" - ​​"receive"). The qstore() function places an element at the end of the queue, and the qretrieve() function removes an element from the beginning of the queue and returns its value. The table shows the sequence of such operations.

    Action Queue Contents
    qstore(A) A
    qstore(B) A B
    qstore(C) A B C
    qretrieve() returns A B C
    qstore(D) B C D
    qretrieve() returns B C D
    qretrieve() returns C D

    Keep in mind that the fetch operation removes an element from the queue and destroys it unless it is stored somewhere else. Therefore, after all elements are retrieved, the queue will be empty.

    In programming, queues are used to solve many problems. One of the most popular types of such tasks is simulation. Queues are also used in operating system task schedulers and in I/O buffering.

    /* Mini event scheduler */

    #include

    #include

    #include

    #include

    char *p, *qretrieve(void);

    void enter(void), qstore(char *q), review(void), delete_ap(void);

    for(t=0; t< MAX; ++t) p[t] = NULL; /* иницилизировать массив

    empty pointers */

    printf("Enter (E), List (L), Delete (R), Exit (Q): ");

    *s = toupper(*s);

    /* Insert a new appointment into the queue. */

    void enter(void)

    printf("Enter appointment %d: ", spos+1);

    if(*s==0) ​​break; /* no recording was made */

    p = (char *) malloc(strlen(s)+1);

    printf("Not enough memory.\n");

    if(*s) qstore(p);

    /* View the contents of the queue. */

    void review(void)

    for(t=rpos; t< spos; ++t)

    printf("%d. %s\n", t+1, p[t]);

    /* Remove an appointment from the queue. */

    void delete_ap(void)

    if((p=qretrieve())==NULL) return;

    printf("%s\n", p);

    /* Insert an appointment. */

    void qstore(char *q)

    printf("List Full\n");

    /* Retrieve an appointment. */

    char *qretrieve(void)

    if(rpos==spos) (

    printf("No more meeting.\n");

    return p;

    List.

    A singly linked cyclic list is a recursive declaration of structures, or rather a pointer to it in the type structure itself:

    int data;//data field

    s *next;//next element

    ) *first,*curr;//first and current element

    Initialization:

    first->next=curr;

    to get the first element use first->data

    to add a new element: curr->next=new s;

    curr=curr->next;//go to the last one

    and to get, for example, the 50th element, loop through the list:

    curr=first;//go to first

    for(int i=0;i<50;i++)

    if(curr->next!=NULL)

    curr=curr->next;


    Related information.


    Typically, the amount of memory required for a variable is specified before the compilation process by declaring the variable. If there is a need to create a variable whose size is unknown in advance, then dynamic memory is used. Reservation And liberation memory leaks in C++ programs can occur at any time. Operations are carried out distribution memory in two ways:

    • using the function malloc, calloc, realloc And free;
    • through the operator new And delete.

    Function malloc reserves a contiguous block of memory cells to store the specified object and returns a pointer to the first cell of that block. The call to the function looks like:

    void *malloc(size);

    Here size- an unsigned integer value that determines the size of the allocated memory area in bytes. If the memory reservation was successful, the function returns a variable of type void *, which can be cast to any desired pointer type.

    Function - calloc also intended for memory allocation. The entry below means it will be highlighted num elements by size byte.

    void *calloc(nime, size);

    This function returns a pointer to the selected area or NULL when it is impossible to allocate memory. A special feature of the function is to reset all selected elements to zero.

    Function reallocresize previously allocated memory. Address her like this:

    char *realloc (void *p, size);

    Here p- pointer to the memory area whose size needs to be changed to size. If the address of a memory area changes as a result of the function, the new address will be returned as a result. If the actual value of the first parameter NULL, then the function realloc works the same as the function malloc, that is, it allocates a memory area of ​​size size byte.

    To free allocated memory, use the function free. Address her like this:

    void free(void *p size);

    Here p- pointer to a memory location previously allocated by functions malloc, calloc or realloc.

    Operators new And delete similar functions malloc And free. New allocates memory, and its only argument is an expression specifying the number of bytes to be reserved. The operator returns a pointer to the beginning of the allocated memory block. Operator delete frees memory, its argument is the address of the first cell of the block that needs to be freed.

    Dynamic array- an array of variable length, memory for which is allocated during program execution. Memory allocation is carried out by functions calloc, malloc or operator new. The address of the first element of the allocated memory location is stored in a variable declared as a pointer. For example, the following statement means that a pointer is described mas and it is assigned the address of the beginning of a contiguous region of dynamic memory allocated using the operator new:

    int *mas=new int;

    The amount of memory allocated is sufficient to store 10 int values.

    In fact, in the variable mas The address of the zero element of the dynamic array is stored. Therefore, the address of the next, first element in the allocated memory area is mas+1, a mas+i is the address of the i-th element. The i-th element of a dynamic array can be accessed as usual with mas[i], or in another way *(mas +i) . It is important to ensure that you do not exceed the boundaries of the allocated memory area.

    When a dynamic array (at any time during program operation) is no longer needed, the memory can be freed using the function free or operator delete.

    I propose to consider several tasks that reinforce this lesson:

    Problem 1

    Find the sum of real elements of a dynamic array.

    //An example of using the malloc and free functions #include "stdafx.h" #include using namespace std; int main() ( setlocale(LC_ALL,"Rus"); int i, n; float *a; //pointer to float float s; cout<<"\n"; cin>>n; //entering the array size //allocating memory for an array of n real elements a=(float *)malloc(n*sizeof(float)); cout<<"Введите массив A \n"; //ввод элементов массива for (i=0; i>*(a+i); ) //accumulating the sum of array elements for (s=0, i=0; i

    //An example of using the malloc and free functions

    #include "stdafx.h"

    #include

    using namespace std ;

    int main()

    int i, n;

    float * a ; //pointer to float

    float s ;

    cout<< "\n" ; cin >> n ; //enter array size

    //allocate memory for an array of n real elements

    a = (float * ) malloc (n * sizeof (float ) ) ;

    cout<< "Enter array A\n";

    //input array elements

    for (i = 0 ; i< n ; i ++ )

    cin >> * (a + i) ;

    //accumulation of the sum of array elements

    for (s = 0 , i = 0 ; i< n ; i ++ )

    s += * (a + i) ;

    //output the amount value

    cout<< "S=" << s << "\n" ;

    //freeing memory

    free(a);

    system("pause");

    return 0 ;

    Problem 2

    Modify a dynamic array of integers so that its positive elements become negative and vice versa. To solve the problem, we will multiply each element by -1.

    //Example of using the new and delete operators #include "stdafx.h" #include using namespace std; int main() ( setlocale(LC_ALL,"Rus"); int i, n; //enter the number of array elements cout<<"n="; cin>>n; //memory allocation int *a=new int[n]; cout<<"Введите элементы массива:\n"; //ввод массива for (i=0; i>a[i]; //output the specified array for (i=0; i

    //Example of using the new and delete operators

    #include "stdafx.h"

    #include

    using namespace std ;

    int main()

    setlocale(LC_ALL, "Rus");

    int i, n;

    //enter the number of array elements

    cout<< "n=" ; cin >> n ;

    //memory allocation

    int * a = new int [ n ] ;

    cout<< "Enter array elements:\n";

    //input array

    While collecting information to write this article, I remembered my first acquaintance with pointers - I was so sad... Therefore, after reading several sections on this topic from various books about programming in C++, it was decided to take a different route and present the topic of C++ Pointers in the order in which I consider necessary. I’ll give you a short definition right away and we’ll look at pointers in action using examples. The next article () will outline the nuances, the use of pointers with C-style strings (character arrays) and the main things to remember.

    A pointer in C++ is a variable that stores the address of data (values) in memory, and not the data itself.

    After looking at the following examples, you will understand the main thing - why we need pointers in programming, how to declare and use them.

    Let's say in a program we need to create an integer array, the exact size of which we do not know before the program starts. That is, we do not know how many numbers the user will need to enter into this array. Of course, we can play it safe and declare an array of several thousand elements (for example, 5,000). This (in our subjective opinion) should be enough for the user to work. Yes – indeed – this may be enough. But let's not forget that this array will take up a lot of space in RAM (5,000 * 4 (int type) = 20,000 bytes). We have secured ourselves, and the user will only fill 10 elements of our array. It turns out that there are actually 40 bytes in use, and 19,960 bytes are wasting memory.

    unreasonable use of RAM

    #include using namespace std; int main() ( setlocale(LC_ALL, "rus"); const int SizeOfArray = 5000; int arrWithDigits = (); cout<< "Массив занял в памяти " << sizeof(arrWithDigits) << " байт" << endl; int amount = 0; cout << "Сколько чисел вы введёте в массив? "; cin >>amount; cout<< "Реально необходимо " << amount * sizeof(int) << " байт" << endl; for (int i = 0; i < amount; i++) { cout << i + 1 << "-е число: "; cin >> arrWithDigits[i]; ) cout<< endl; for (int i = 0; i < amount; i++) { cout << arrWithDigits[i] << " "; } cout << endl; return 0; }

    #include

    using namespace std ;

    int main()

    const int SizeOfArray = 5000 ;

    int arrWithDigits [ SizeOfArray ] = ( ) ;

    cout<< "The array occupied in memory"<< sizeof (arrWithDigits ) << " байт" << endl ;

    int amount = 0 ;

    cout<< "How many numbers will you enter into the array?";

    cin >> amount ;

    cout<< "Really necessary"<< amount * sizeof (int ) << " байт" << endl ;

    for (int i = 0 ; i< amount ; i ++ )

    cout<< i + 1 << "-е число: " ;

    cin >> arrWithDigits [ i ] ;

    cout<< endl ;

    for (int i = 0 ; i< amount ; i ++ )

    cout<< arrWithDigits [ i ] << " " ;

    cout<< endl ;

    return 0 ;

    To a standard library function sizeof() passing the declared array arrWithDigits line 10. It will return to the place of the call the size in bytes that this array occupies in memory. To the question “How many numbers will you enter into the array?” the answer is 10. In line 15, the expression amount * sizeof(int) will become equivalent to 10 * 4, since the function sizeof(int) will return 4 (size in bytes of type int). Next, enter the numbers from the keyboard and the program will display them on the screen. It turns out that the remaining 4990 elements will store zeros. So there's no point in showing them.

    The main information on the screen: the array took 20,000 bytes, but in reality it requires 40 bytes. How to get out of this situation? Someone might want to rewrite the program so that the user enters the size of the array from the keyboard and, after entering the value, declare an array with the required number of elements. But this cannot be done without pointers. As you remember, the size of the array must be a constant. That is, an integer constant must be initialized before the array is declared and we cannot prompt for its input from the keyboard. Experiment and check.


    Here the operator lights us up in red >> since a constant value cannot be changed.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    Here we are warned that the size of the array cannot be the value of a regular variable. Constant value required!

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    In the following code we will use a pointer and operators that are new to you new(allocates memory) and delete(frees memory).

    intelligent use of RAM using pointers

    #include #include using namespace std; int main() ( setlocale(LC_ALL, "rus"); int sizeOfArray = 0; // array size (entered by user) cout<< "Чтобы создать массив чисел, введите его размер: "; cin >> sizeOfArray; // ATTENTION! int* arrWithDigits - declaration of a pointer // to a piece of memory that will be allocated new int* arrWithDigits = new int ; for (int i = 0; i< sizeOfArray; i++) { arrWithDigits[i] = i + 1; cout << arrWithDigits[i] << " "; } cout << endl; delete arrWithDigits; // освобождение памяти return 0; }

    #include

    #include

    using namespace std ;

    int main()

    setlocale(LC_ALL, "rus");

    int sizeOfArray = 0 ; // array size (entered by the user)

    cout<< "To create an array of numbers, enter its size: ";

    cin >> sizeOfArray ;

    // ATTENTION! int* arrWithDigits - pointer declaration

    // to a piece of memory that new will allocate

    int * arrWithDigits = new int [ sizeOfArray ] ;

    for (int i = 0 ; i< sizeOfArray ; i ++ )

    arrWithDigits[i] = i+1;

    cout<< arrWithDigits [ i ] << " " ;

    cout<< endl ;

    delete arrWithDigits ; // freeing memory

    return 0 ;

    The user enters a value from the keyboard - line 12. The pointer is defined below: int * arrWithDigits This entry means that arrWithDigits is a pointer. It is created to store the address of the cell in which the integer will be located. In our case arrWithDigits will point to the array cell with index 0. The sign * - the same as used for multiplication. Based on the context, the compiler will “understand” that this is a pointer declaration and not a multiplication. Next comes the sign = and operator new, which allocates a piece of memory. We remember that our memory should be allocated for an array, and not for a single number. Record new int [sizeOfArray] can be deciphered like this: new(allocate memory) int(for storing integers) (in quantity sizeOfArray ).

    Thus, in line 16 it was defined dynamic array. This means that memory for it will be allocated (or not allocated) while the program is running, and not during compilation, as happens with regular arrays. That is, memory allocation depends on the development of the program and decisions that are made directly in its operation. In our case, it depends on what the user enters into the variable sizeOfArray

    Line 25 uses the operator delete. It releases the operator allocated new memory. Because new allocated memory for storing the array, then when freeing it, you need to make it clear to the compiler that it is necessary to free the memory of the array, and not just its zero cell, which is pointed to arrWithDigits. Therefore, between delete and the pointer name is placed in square brackets delete arrWithDigits ; Remember that every time memory is allocated using new, you need to free this memory using delete. Of course, when the program terminates, the memory it occupied will be automatically freed. But make it a good habit to use operators new And delete in pairs. After all, a program can contain 5-6 arrays, for example. And if you free up memory every time it is no longer needed in the future in a running program, memory will be used more wisely.

    Let's say in our program we filled an array with ten values. Next, we calculated their sum and recorded it in some variable. And that’s it – we won’t work with this array anymore. The program continues to work and new dynamic arrays are created in it for some purpose. In this case, it is advisable to free the memory occupied by the first array. Then, when allocating memory for other arrays, this memory can be reused in the program.

    Let's consider the use of pointers as parameters of functions. To get started, type and compile the following code. In it, the function receives two variables and offers to make changes to their values.

    attempt to change variables passed to a function

    #include #include using namespace std; void changeData(int varForCh1, int varForCh2); int main() ( setlocale(LC_ALL, "rus"); int variableForChange_1 = 0; int variableForChange_2 = 0; cout<< "variableForChange_1 = " << variableForChange_1 << endl; cout << "variableForChange_2 = " << variableForChange_2 << endl; cout << endl; changeData(variableForChange_1, variableForChange_2); cout << endl; cout << "variableForChange_1 = " << variableForChange_1 << endl; cout << "variableForChange_2 = " << variableForChange_2 << endl; return 0; } void changeData(int varForCh1, int varForCh2) { cout << "Введите новое значение первой переменной: "; cin >>varForCh1; cout<< "Введите новое значение второй переменной: "; cin >> varForCh2; )

    #include

    #include

    using namespace std ;

    void changeData (int varForCh1 , int varForCh2 ) ;

    int main()

    setlocale(LC_ALL, "rus");

    int variableForChange_1 = 0 ;

    int variableForChange_2 = 0 ;

    cout<< "variableForChange_1 = " << variableForChange_1 << endl ;

    cout<< "variableForChange_2 = " << variableForChange_2 << endl ;

    cout<< endl ;

    changeData(variableForChange_1, variableForChange_2);

    cout<< endl ;

    cout<< "variableForChange_1 = " << variableForChange_1 << endl ;

    cout<< "variableForChange_2 = " << variableForChange_2 << endl ;

    return 0 ;

    void changeData(int varForCh1, int varForCh2)

    cout<< "Enter a new value for the first variable: ";

    cin >> varForCh1 ;

    cout<< "Enter a new value for the second variable: ";

    cin >> varForCh2 ;

    Run the program and enter new variable values. As a result, you will see that upon completion of the function, the variables have not changed and are equal to 0.

    As you remember, the function does not work directly with variables, but creates their exact copies. These copies are destroyed after the function exits. That is, the function received some variable as a parameter, created a copy of it, worked with it and destroyed it. The variable itself will remain unchanged.

    Using pointers, we can pass variable addresses to a function. Then the function will be able to work directly with variable data at the address. Let's make changes to the previous program.

    changing variable values ​​using pointers

    #include #include using namespace std; void changeData(int* varForCh1, int* varForCh2); int main() ( setlocale(LC_ALL, "rus"); int variableForChange_1 = 0; int variableForChange_2 = 0; cout<< "variableForChange_1 = " << variableForChange_1 << endl; cout << "variableForChange_2 = " << variableForChange_2 << endl; cout << endl; changeData(&variableForChange_1, &variableForChange_2); cout << endl; cout << "variableForChange_1 = " << variableForChange_1 << endl; cout << "variableForChange_2 = " << variableForChange_2 << endl; return 0; } void changeData(int* varForCh1, int* varForCh2) { cout << "Введите новое значение первой переменной: "; cin >> *varForCh1; cout<< "Введите новое значение второй переменной: "; cin >> *varForCh2; )

    The first timer on this website, so it goes here.

    I am new to C++ and I am currently working on the book "Data Structures Using C++ 2nd ed, D.S. Malik".

    In the book, Malik offers two ways to create a dynamic two-dimensional array. In the first method, you declare a variable as an array of pointers, where each pointer is of type integer. eg

    Int *board;

    And then use for-loop to create "columns" when using an array of pointers as "rows".

    Second method, you use a pointer to a pointer.

    Int **board; board = new int* ;

    My question is: which method is better? The ** method is easier for me to visualize, but the first method can be used in much the same way. Both methods can be used to create dynamic 2-dimensional arrays.

    Edit: Wasn't clear enough as stated above. Here's the code I tried:

    Int row, col; cout<< "Enter row size:"; cin >>row; cout<< "\ncol:"; cin >>col; int *p_board; for (int i=0; i< row; i++) p_board[i] = new int; for (int i=0; i < row; i++) { for (int j=0; j < col; j++) { p_board[i][j] = j; cout << p_board[i][j] << " "; } cout << endl; } cout << endl << endl; int **p_p_board; p_p_board = new int* ; for (int i=0; i < row; i++) p_p_board[i] = new int; for (int i=0; i < row; i++) { for (int j=0; j < col; j++) { p_p_board[i][j] = j; cout << p_p_board[i][j] << " "; } cout << endl; }

    4 answers

    The first method cannot be used to create dynamic 2D arrays because:

    Int *board;

    you have essentially allocated an array of 4 pointers to int per stack. So if you now fill each of these 4 pointers with a dynamic array:

    For (int i = 0; i< 4; ++i) { board[i] = new int; }

    what you end up with is a 2D array with static the number of lines (in this case 4) and dynamic number of columns (in this case 10). Thus, the dynamics are not fully, since when allocating an array on the stack you should indicate constant size, i.e. Known in time. Dynamic the array is called dynamic, because its size does not have to be known in compile time, but rather can be determined by some variable in during execution.

    Once again when you do:

    Int *board;

    Const int x = 4; //<--- `const` qualifier is absolutely needed in this case! int *board[x];

    you provide a constant known in compile time(in this case 4 or x) so that the compiler can now pre-select this memory for your array, and when your program is loaded into memory, it will already have this amount of memory for the board array, which is why it is called static, i.e. because the size hard coded And cannot change dynamically(at runtime).

    On the other hand, when you do:

    Int **board; board = new int*;

    Int x = 10; //<--- Notice that it does not have to be `const` anymore! int **board; board = new int*[x];

    the compiler doesn't know how much memory the board array will require, so it doesn't allocates in advance All. But when you run your program, the size of the array will be determined by the value of the x variable (at runtime), and the corresponding space for the board array will be allocated to the so-called a bunch- an area of ​​memory in which all programs running on your computer can allocate unknown in advance(at compile time) summarizes memory for personal use.

    As a result, to actually create a dynamic 2D array, you need to go with the second method:

    Int **board; board = new int*; // dynamic array (size 10) of pointers to int for (int i = 0; i< 10; ++i) { board[i] = new int; // each i-th pointer is now pointing to dynamic array (size 10) of actual int values }

    We've just created a 10 by 10 square 2D array. To go through it and fill it with actual values, like 1, we could use nested loops:

    For (int i = 0; i< 10; ++i) { // for each row for (int j = 0; j < 10; ++j) { // for each column board[i][j] = 1; } }

    What you describe for the second method only produces a 1D array:

    Int *board = new int;

    This simply allocates an array with 10 elements. Perhaps you meant something like this:

    Int **board = new int*; for (int i = 0; i< 4; i++) { board[i] = new int; }

    In this case, we allocate 4 int* s and then each point to a dynamically allocated array of 10 int s.

    So now we compare this to int* board; . The main difference is that when using such an array, the number of "rows" must be known at compile time. This is because arrays must have fixed compile-time sizes. You may also have a problem if you want to perhaps return this array from int* s, since the array will be destroyed at the end of its scope.

    A method that dynamically allocates both rows and columns requires more complex measures to avoid memory leaks. You should free the memory like this:

    For (int i = 0; i< 4; i++) { delete board[i]; } delete board;

    I have to recommend using a standard container instead. You can use std::array 4> or perhaps std::vector > which you initialize with the appropriate size.

    In both cases, your inner dimension can be dynamically set (i.e. taken from a variable), but the difference is in the outer dimension.

    This question is basically equivalent to the following:

    Is int* x = new int; "better" than int x ?

    The answer is "no, unless you need to choose that array size dynamically."

    This code works well with very few external library requirements and shows basic use of int **array .

    This answer shows that the array each has a dynamic size and also how to assign a dynamically sized linear array to a dynamically sized branch array.

    This program takes arguments from STDIN in the following format:

    2 2 3 1 5 4 5 1 2 8 9 3 0 1 1 3

    The code for the program is below...

    #include int main() ( int **array_of_arrays; int num_arrays, num_queries; num_arrays = num_queries = 0; std::cin >> num_arrays >> num_queries; //std::cout<< num_arrays << " " << num_queries; //Process the Arrays array_of_arrays = new int*; int size_current_array = 0; for (int i = 0; i < num_arrays; i++) { std::cin >> size_current_array; int *tmp_array = new int; for (int j = 0; j< size_current_array; j++) { int tmp = 0; std::cin >>tmp; tmp_array[j] = tmp; ) array_of_arrays[i] = tmp_array; ) //Process the Queries int x, y; x = y = 0; for (int q = 0; q< num_queries; q++) { std::cin >> x >> y; //std::cout<< "Current x & y: " << x << ", " << y << "\n"; std::cout << array_of_arrays[x][y] << "\n"; } return 0; }

    This is a very simple implementation of int main and only depends on std::cin and std::cout . Barebones, but good enough to show how to work with simple multidimensional arrays.

    Purpose of the lecture: study declarations, allocation and release of memory for one-dimensional dynamic arrays, accessing elements, learn to solve problems using one-dimensional dynamic arrays in the C++ language.

    When using many data structures, it often happens that they must have a variable size depending on the size of the data structure. lead time programs. In these cases it is necessary to use dynamic memory allocation. One of the most common such data structures are arrays, in which the size is not initially defined or fixed.

    According to language standard An array is a collection of elements, each of which has the same attributes. All these elements are placed in adjacent memory locations in a row, starting from the address corresponding to the beginning of the array. That is, the total number of elements of the array and the size of the memory allocated for it are completely and uniquely specified by the definition of the array. But this is not always convenient. Sometimes it is required that the allocated memory for an array be sized to solve a specific problem, and its size is not known in advance and cannot be fixed. The formation of arrays with variable sizes (dynamic arrays) can be organized using pointers and tools dynamic memory allocation.

    Dynamic array is an array whose size is not fixed in advance and can change during program execution. To resize dynamic array programming language C++, which supports such arrays, provides special built-in functions or operations. Dynamic arrays provide the opportunity for more flexible work with data, since they allow you not to predict the stored volumes of data, but to adjust the size of the array in accordance with the actually required volumes.

    Declaring one-dimensional dynamic arrays

    Under the declaration of one-dimensional dynamic array understand the declaration of a pointer to a variable of a given type so that this variable can be used as dynamic array.

    Syntax:

    Type *ArrayName;

    Type – type of elements being declared dynamic array. Elements dynamic array Functions and elements cannot be of type void .

    For example:

    int *a; double *d;

    In these examples, a and d are pointers to the beginning of the allocated memory location. Pointers take the value of the address of the allocated memory area for values ​​of type int and type double, respectively.

    Thus, when dynamically allocating memory for dynamic arrays, you should describe the corresponding pointer to which the value of the address of the beginning of the allocated memory area will be assigned.

    Allocation of memory for a one-dimensional dynamic array

    In order to allocate memory for one-dimensional dynamic array There are 2 ways in C++.

    1) by operation new , which allocates a section of dynamic memory of the appropriate size for storing the array and does not allow the array elements to be initialized.

    Syntax:

    ArrayName = new Type [ConstantTypeExpression];

    ArrayName – array identifier, that is, the name of the pointer for the allocated memory block.

    TypeExpressionConstant– sets the number of elements ( dimension) of the array. An expression of constant type is evaluated at compile time.

    For example:

    int *mas; mas = new int ; /*allocate dynamic memory of 100*sizeof(int) bytes*/ double *m = new double [n]; /*allocate dynamic memory of n*sizeof(double) bytes*/ long (*lm); lm = new long ; /*allocate dynamic memory of 2*4*sizeof(long) bytes*/

    When allocating dynamic memory, the dimensions of the array must be fully specified.

    2) using a library function malloc (calloc) , which is used to allocate dynamic memory.

    Syntax:

    ArrayName = (Type *) malloc(N*sizeof(Type));

    ArrayName = (Type *) calloc(N, sizeof(Type));

    ArrayName – array identifier, that is, the name of the pointer for the allocated memory block.

    Type – the type of a pointer to an array.

    N – number of array elements.

    For example:

    float *a; a=(float *)malloc(10*sizeof(float)); // or a=(float *)calloc(10,sizeof(float)); /*allocate dynamic memory of 10*sizeof(float) bytes*/

    Since the malloc(calloc) function returns untyped pointer void * , then it is necessary to convert the resulting