[C] 6. Complex structures and pointers

Posted by jhuedder on Sun, 26 Dec 2021 03:33:26 +0100

structural morphology

  • Computer can solve the problems that can be calculated in reality. First, we should express the data of the real problems
  • To store some information, define the corresponding variable with the corresponding type, and store the value in the variable
  • As long as it is a variable, it occupies a certain amount of space in memory
  • Structure is a more complex type, which contains various types of fields, which are used to resolve this more complex type
  1. Define structure variables
    Using struct + structure name in C language
    The struct keyword is not added in C + +, because struct is a class in C + +
  2. There are two ways to access structure members:
    . Direct reference
    ->Indirect access

Structure memory alignment principle

  1. When opening up space, align according to the basic data type with the largest number of bytes
  2. Due to the alignment principle, when the type and number of fields in the structure are the same, the occupied memory size is related to the order
  3. There are two ways to save memory:
    1. The fields of the same type are defined in the same order
    2. #pragma pack(n) changes the alignment. pragma is a predefined macro
#pragma pack(1)
typedef struct NODE {
  short a;
  int b;
  char c;
} NODE;

/*-----   Notes-----*/
1.By default, the data type with the largest number of bytes in the structure is used as the alignment standard, sizeof(NODE)=12
2.#pragma pack(1), unaligned, 1B aligned, sizeof(NODE)=7
  Compiler from“ n"And "the longest data type length in the structure", select the smaller one as the alignment standard

Calculate the structure offset - 25 pointer. cpp

#include <stdio.h>
#Define offset (T, a) (long) (& ((t *) (null)) - > A)) / / long use% ld

struct Data {
    int a;
    double b;
    char c;
};

int main() {
    int num = 0x0626364; // Small terminal: 64 63 62 0
    printf("%s\n", (char *)(&num)); // 'd' 'c' 'b' '\0'
    printf("%ld\n", offset(struct Data, a)); // long using% ld
    printf("%ld\n", offset(struct Data, b));
    printf("%ld\n", offset(struct Data, c));
    return 0;
}
  1. Cast NULL address, no variables need to be defined
  2. Calculate the offset of each field of the structure, and define the temp variable in the offset macro
#define offset(T, a) ({\
    T temp;\
    (char *)(&temp.a) - (char *)(&temp);\
})

Common body

  • Also known as a union, it also defines a more complex type. The keyword struct is replaced by union

As long as it is a variable, it will occupy the corresponding space

  • The common body shares the same space, and the space size is the size of the field with the largest space
  1. The common body in the figure above has two fields: a structure and an unsigned integer
  2. Use anonymous structure, struct {...} bytes; Structure name missing
    Anonymous structure is legal, but it can only be initialized once during definition, and it will not be found later

Exercise 3 Use the common body to realize the function of ip to integer

#include <stdio.h>

union IP {
    struct {
        unsigned char a1;
        unsigned char a2;
        unsigned char a3;
        unsigned char a4;
    } ip;//Anonymous structure
    unsigned int num;
};

int main() {
    union IP p;
    char str[100];//ip is read in as a string
    int arr[4];
    while (~scanf("%s", str)) {
        //Take out the number in "192.168.0.1"
        sscanf(str, "%d.%d.%d.%d", arr, arr + 1, arr + 2, arr + 3);
        //Small terminal: digital low - > low address
        p.ip.a1 = arr[3];
        p.ip.a2 = arr[2];
        p.ip.a3 = arr[1];
        p.ip.a4 = arr[0];
    	printf("%u\n", p.num);//Unsigned integer% u
    }
    return 0;
}
  1. Why can IP be converted to integer?
    IP form: XXX XXX. XXX. 30. The range of XXX is 0-255 (255 is 8 1s), which requires 8 binary bits (1 byte) and is of unsigned type. Four XXX are 4 bytes, so an IP can correspond to an unsigned integer value

  2. sscanf() is used for clipping and sprintf() is used for splicing of formatted strings

Large and small terminal machines

Small terminal, digital low bit ----- low address bit
Large terminal, digital low bit ----- high address

  1. Assign low bit to low address (note)

    192.168. 0.1 the low order is 1, and the string input is p.ip A4, lower address arr[0]
//Correct assignment
p.ip.a1 = arr[3];
p.ip.a2 = arr[2];
p.ip.a3 = arr[1];
p.ip.a4 = arr[0];
  1. Assign int type to char type?
    0-255 integers are stored in byte 0 in the small terminal, and there is no problem assigning them directly to the char type array

  2. The input IP is 192.168 0.1 and 192.168 There is a difference of 1 between 0.2, but the integer results mapped by them do not differ by 1 because of the wrong assignment

//Wrong assignment
p.ip.a1 = arr[0];
p.ip.a2 = arr[1];
p.ip.a3 = arr[2];
p.ip.a4 = arr[3];
  1. For the problem that the size of the terminal is uncertain, convert the local byte order to the network byte order (there is a unified standard, and the other party will automatically convert to the corresponding byte order when downloading)

  2. Judge small terminal

int is_little() {
    static int num = 1;//Static variable static
    //num is treated as a 4-byte character array
    return ((char *)(&num))[0];//&After num, it is strongly converted to char *, taking bit 0
}
printf("%d\n", is_little());
  • int integer 1 occupies 4 bytes, and 1 has a low address (on byte 0)
  • Num is regarded as a character array with 4 bytes. After & num, it is strongly converted to char *, taking 0 bits

Pointer and address

  1. Nature of variables:
    Variables are used to store values;
    Variable has space size;
    The variable has an address (the address is numbered by byte, and the address symbol is taken & the address with the lowest number is taken by default)

  2. What do 64 bit and 32-bit operating systems mean?
    The address in memory is addressed with 64 / 32 bits, or the address range of the address
    The 32-bit operating system (0-232-1) can only recognize 4GB of memory (32 addresses of 2), and can't recognize it even with memory modules

  1. Storing and representing addresses with pointer variables (starting with 0X in C language)
  2. No matter what type is pointed to, the space occupied by the pointer type is the same (the purpose of distinguishing types is ± n operation)
    The 64 bit operating system pointer occupies 8 bytes (64bits represents one address), and the 32-bit operating system occupies 4 bytes
  3. Different types of pointers can pass values
    int *p;
    char *q;
    p can be passed to q
  4. int *p;
    *Follow p. p is the pointer variable, which itself represents the content (address) of the variable
    *p value / reverse operation
  5. A pointer variable is also a variable. A variable can store a value. A variable has an address. A variable that stores the address of a pointer variable is called a pointer to a pointer
  6. scanf() understanding
    Scanf writes the value to the variable and passes the variable address (the variable will not report an error). This is not required by the scanf function definition, but our functional logic needs to do so
    When the function is called, the value is passed, and the scope is inside the function, & the address of the external parameter is passed in as a variable. When scanf writes the value, it is written in the memory corresponding to the address, and the value still exists when accessed outside the function
  7. Important concepts
  • p+1 is the number of bytes of the element type skipped backward (the reason for distinguishing the pointer type is also because the operation of ± 1 is involved), which is equivalent to & p [1]. p is an array, which can be used in this way
  • *p=a, so the third equation holds

Function pointer

  • As mentioned in the array, when functions are passed around as parameters, we need to define variables that store function information, which are called function pointer variables

  • Define variable: type name + variable name

  1. Define function pointer variables
    int (*add)(int, int); Function pointer
    int *add(int, int); Function declaration, return value type int*

  2. typedef promotes a variable to a type
    add is promoted from a function pointer variable to a function pointer type

Usage of typedef

  1. Structure type, structure pointer type rename
  2. Function pointer naming:
    Func is a function pointer variable, which can be promoted to a function pointer type, func a; Define a as a function pointer variable

Difference between define and typedef - 25 pointer. cpp

#include <stdio.h>

// The difference between define/typedef
#define ppchar char *
typedef char * pchar;

int main() {  
    ppchar p1, p2;
    pchar p3, p4;
    printf("p1 = %lu, p2 = %lu\n", sizeof(p1), sizeof(p2));
    printf("p3 = %lu, p4 = %lu\n", sizeof(p3), sizeof(p4));
    return 0;
}
  1. g++ -E 25.pointer.cpp check the precompiled code. The p2 type is char, not char*
  2. define simple symbol substitution (p1 type is char *,p2 type is char)
    typedef rename (type P3 and P4 are char *)

main function

  1. The operating system calls the main function, the operating system passes parameters (with parameters), and the return value is given to the operating system
    int main(); Function last return 0; The 0 value of is returned to the operating system

  2. linux operating system, $? Judge whether the last command executed by the operating system is successful, return 0 success, and non-0 value is unsuccessful

  3. Number of arguments on the int argc command line
    char *argv [], string form of command line parameter

    argv is an array, and each bit in the array is char*
    Equivalent to char **argv
    *It is equivalent to [], so it is also equivalent to char [] []. One dimensional array is a string, and two-dimensional array is a pile of strings

  4. char **env environment variable

Main parameter explanation - 26 main. cpp

#include <stdio.h>
#include <string. h> / / strncmp and strcmp
#include <stdlib.h> // exit(0)

void output(int argc, char *argv[], char *env[]) {
    printf("argc = %d\n", argc);
    for (int i = 0; i < argc; i++) {
        printf("argv[%d] = %s\n", i, argv[i]);
    }
    for (int i = 0; env[i]; i++) {
        if (!strncmp(env[i], "USER=", 5)) { // A env[i] first 5 digits "USER ="
            if (!strcmp(env[i] + 5, "xzh")) { // User name "xzh" (custom), program fingerprint identification function
                printf("Welcome capatain Xu!\n");
            } else {
                printf("you are not USER! please gun!\n");
                exit(0);
            }
        }
        // printf("env[%d] = %s\n", i, env[i]); //  Print env
    }
    return ;
}

int main(int argc, char *argv[], char **env) {
    output(argc, argv, env);
    return 0;
}
  1. argc and argv
  2. env
  3. Using "USER = * * *" in env for program fingerprint identification

Topics: C