# C language improvement

## Structure array sorting

On the basis of the previous program, add the age variable to the structure, and then sort it according to the age of (Teacher)
Define structure:

```typedef struct Teacher
{
int age;
char **stu;	//Two dimensional memory
}Teacher;
```

First assign a value to age, and then compare the size of age.
Notice how it's exchanged.

```void sortArray(Teacher* q, int n)
{
int i, j;
Teacher tmp;
for (i = 0; i < n - 1; i++)
{
for (j = i + 1; j < n; j++)
{
if (q[i].age < q[j].age)
{
//Descending order
tmp = q[i];
q[i] = q[j];
q[j] = tmp;
}
}
}
}
```

Main function call

```	sortArray(q,3);
```

## Deep copy and shallow copy of structure

### Shallow copy

Define two structural variables of the same type and assign a value to one of them. There are pointer type variables in this structure. Therefore, it is necessary to open up space in the heap area. After the assignment is completed, assign the structure to another structure directly.

```#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct Teacher
{
char* name;
int age;
}Teacher;

int main(int argc,char *argv[])
{
Teacher t1;
t1.name = (char*)malloc(30);
strcpy(t1.name, "Lili");
t1.age = 22;

Teacher t2;

t2 = t1;
printf("[t2]-name:%s,age = %d.\n", t2.name,t2.age);

printf("\n");
system("pause");
return 0;
}
```

Drawing analysis: From the figure, we can see that after the assignment, the two pointers point to the same pile of memory, which is the shallow copy.
After the main function of the program is completed, the heap memory space needs to be released. Should we release it once or twice? If the number of programs is large, do we need to release every shallow copy.
For C language, you only need to release the opening space once.

```	if (t1.name!=NULL)
{
free(t1.name);
t1.name = NULL;
}
```

If you release multiple times, you will report an error. The reason is that the same memory can only be released once.

### Deep copy

```#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct Teacher
{
char* name;
int age;
}Teacher;

int main(int argc,char *argv[])
{
Teacher t1;
t1.name = (char*)malloc(30);
strcpy(t1.name, "Lili");
t1.age = 22;

Teacher t2;

t2 = t1;
//Deep copy: allocate space artificially and dynamically, and then copy again.
t2.name = (char*)malloc(30);
strcpy(t2.name, t1.name);

printf("[t2]-name:%s,age = %d.\n", t2.name,t2.age);

if (t1.name!=NULL)
{
free(t1.name);
t1.name = NULL;
}

//It's okay to release now.
if (t2.name != NULL)
{
free(t2.name);
t2.name = NULL;
}

printf("\n");
system("pause");
return 0;
}
```

Drawing analysis: Conclusion: shallow copy and deep copy have little effect on c language. But it will have an impact on c + +. The shallow copy only needs to be released once, while the deep copy is opened once and released once.

## Offset of structure

After the structure type is defined, the memory layout of internal member variables (the offset of each member in memory) has been determined.

### verification

```#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//After the structure type is defined, the memory layout of internal member variables (the offset of each member in memory) has been determined
typedef struct Teacher
{
char name;//64
int age;//4
int id;//4
}Teacher;

int main(int argc,char *argv[])
{
Teacher t1;
Teacher* p = NULL;
p = &t1;

//Offset under test
//&(P - > age), the priority of the arrow is high, and whether it is added or not will not affect it.
int n1=(int)(&p->age)- (int)p;//Relative to the first address of the structure
printf("n1 = %d .", n1);

int n2 = (int)&((Teacher* )0)->age;//Offset of absolute 0 address
printf("n2 = %d .", n2);

printf("\n");
system("pause");
return 0;
}
```

Output result: ## Byte alignment of structure

### Default environment unit alignment

Windows default 8-byte alignment
Linux 32-bit default 4-byte alignment, 64 bit default 8-byte alignment

### Ordinary variable (including array) type

Principle 1: alignment rules of data members (in the largest type bytes).

For the data member of struct, the first data member is placed where the offset is 0, and then each data member is stored where the offset is an integer multiple of the size of the data member (for example, if int is 4 bytes in 32-bit machine, it should be stored from the address of an integer multiple of 4)

Principle 2: the total size of the structure, that is, the result of sizeof, must be an integral multiple of its largest internal member, and any deficiency must be filled in.

#### Example 1

Let's take a simple example:

```#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc,char *argv[])
{
//After the structure type is defined, the memory layout of internal member variables (the offset of each member in memory) has been determined
struct
{
int a;  //int takes up 4 bytes
short b;//short takes up 2 bytes
}A;

//The alignment unit is 4 bytes

//Offset:
//a: 4 * 0 = 0
//b : 2 * 2 = 4
printf("sizeof(A) = %d .", sizeof(A));

printf("\n");
system("pause");
return 0;
}
```

analysis:  Output result: #### Example 2 structure member variables are the same, but the member order is different.

##### 1,
```#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc,char *argv[])
{
//After the structure type is defined, the memory layout of internal member variables (the offset of each member in memory) has been determined
struct
{
int a;
char b;
short c;
}A;

//Alignment unit: 4 bytes

//a: 4 * 0 = 0
//b: 1 * 4 = 4
//c: 2 * 3 = 6

printf("sizeof(A) = %d .", sizeof(A));

printf("\n");
system("pause");
return 0;
}
```

analysis: Output result: ##### 2. Adjust the order of lower structure members
```#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc,char *argv[])
{
//After the structure type is defined, the memory layout of internal member variables (the offset of each member in memory) has been determined
struct
{
char b;
int a;
short c;
}A;

//Alignment unit: 4 bytes

//b: 1 * 0 = 0
//a: 4 * 1 = 4
//c: 2 * 4 = 8

printf("sizeof(A) = %d .", sizeof(A));

printf("\n");
system("pause");
return 0;
}
```

analysis: Output result: #### Example 3 structure with array members.

The analysis is the same. Arrays such as char a are still calculated according to the bytes occupied by char.
For example, the maximum number of bytes in the current structure is int type, that is, four bytes. In my structure, char a, if one line is not enough for me to save, I will save another line.

```#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc,char *argv[])
{
//After the structure type is defined, the memory layout of internal member variables (the offset of each member in memory) has been determined
struct
{
int a;
char b;
short c;
}A;

//Alignment unit: 4 bytes

//a: 4 * 0 = 0
//b: 1 * 4 = 4
//c: 2 * 6 = 12

printf("sizeof(A) = %d .", sizeof(A));

printf("\n");
system("pause");
return 0;
}
``` Output result: ### Nested structure in structure

Based on the above two principles.
Principle 3: compare the largest data type in the nested structure with the data type with the largest byte in the structure, and take the larger one for alignment.

Principle 4: if one structure B is nested with another structure a, compare the data type with the largest byte in the two structures, and then align according to the byte. After the other members in structure B are aligned according to principle 1, structure A shall be stored from the integer multiple of the maximum aligned byte (the ordinary members that were not full before will not be saved). Ordinary members in the structure are also stored according to principle 1. Finally, we should follow principle 3. The total size of the structure, that is, the result of sizeof, must be an integer multiple of its largest internal member, and the deficiencies should be supplemented.

#### Example 4 nested structure A in structure B

##### Structure A is the last member variable in structure B
```#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc,char *argv[])
{
struct A
{
int a;
double b;
float c;
};

struct
{
char e;
int f;
double g;
short h;
struct A;
}B;

//Normal member offset
//e: 1 * 0 = 0
//f: 4 * 1 = 4
//g: 8 * 1 = 8
//h: 2 * 8 = 16

//Record the coordinates of the starting point of the structure
// 8 * 3 = 24
//Structure member offset
//a: 24 + 4 * 0 = 24
//b: 24 + 8 * 1 = 32
//c: 24 + 4 * 4 = 40

printf("sizeof(A) = %d .", sizeof(B));

printf("\n");
system("pause");
return 0;
}
``` Output result: ##### Structure A is not the last member variable in structure B
```#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc,char *argv[])
{
struct A
{
int a;
double b;
float c;
};

struct
{
char e;
int f;
double g;
short h;
struct A;
char d;
}B;

//Normal member offset
//e: 1 * 0 = 0
//f: 4 * 1 = 4
//g: 8 * 1 = 8
//h: 2 * 8 = 16

//Record the coordinates of the starting point of structure A
// 8 * 3 = 24
//Structure member offset
//a: 24 + 4 * 0 = 24
//b: 24 + 8 * 1 = 32
//c: 24 + 4 * 4 = 40

//Record the starting point coordinates of common variables after the end of structure A
// 8 * 6 = 48
//d: 48 + 1 * 0 = 48

printf("sizeof(A) = %d .", sizeof(B));

printf("\n");
system("pause");
return 0;
}
``` Output result: ### Specifies the alignment of structural units

#### Use #pragma pack(n) to specify the alignment units

Use #pragma pack(n) to specify the alignment unit. N takes 1, 2, 4, 8 and 16
But it cannot exceed the longest member in the structure. For example, the int type is 4 bytes, but I specify that the structure alignment is in units of 2. If one line is not enough, save another line.

When I specify that the structure alignment is in units of 2, for int type is 4 bytes, one line is saved, and then one line is saved.

When the specified alignment unit is 1, it is best to calculate sizeof. You only need to add the number of bytes occupied by the data type of each variable directly.

```#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc,char *argv[])
{
#pragma pack(1)

struct
{
int d;
char a;
short c;
char b;
}B;

printf("sizeof(B) = %d .", sizeof(B));

printf("\n");
system("pause");
return 0;
}
```

Output result: #### Use #pragma pack(n) to specify the alignment units

A major feature of GNU C (but not known to beginners) is __ attribute _ Mechanism_ attribute _ _ You can set Function Attribute, Variable Attribute and Type Attribute.

_ _ attribute _ _ The syntax format is:
_ _ attribute _ _((attribute-list))

Its position constraint is: put at the end of the Declaration " Before.

Packed is a parameter of the Type Attribute. Using packed can reduce the space occupied by the object. It should be noted that the effect of attribute attribute is also related to your connector. If your connector only supports 16 byte alignment at most, it is useless for you to define 32 byte alignment at this time.

Use the packed attribute to define the struct or union type and set the memory constraint of each variable of its type. When the type of integrate should be used, it implies that the type of integrate should be used.

In the following example, the values in the variable array of my packed struct type will be compact, but the internal member variable s will not be "packed". If you want the internal member variable to be packed, my unpacked struct also needs to use packed for corresponding constraints.

```struct my_unpacked_struct
{
char c;
int i;
};

struct my_packed_struct
{
char c;
int i;
struct my_unpacked_struct s;
}__attribute__ ((__packed__));
```

Memory alignment is often done by the compiler. If you use gcc, you can add it when defining variables__ attribute__， To decide whether to use memory alignment or align memory to several bytes. Take the above structure as an example:

1. Specify 4-byte alignment, and you can also specify alignment to 8 bytes.

```struct student
{
char name;
uint32_t id;
char subject;
} __attribute__ ((aligned(4)));
```

2. Tell the compiler that the length of the structure is the sum of the length of each variable

```struct student
{
char name;
uint32_t id;
char subject;
} __attribute__ ((packed));
```

# file

## Basic concepts of documents

To import header file #include < stdio h>

### Classification of documents  ### file buffer

ANSI C standard library functions only have file buffers, which are not available for system calls, such as write, read, etc.

The file buffer can be understood as an array defined by the operating system to improve efficiency.
For example, if A teacher asks classmate A to run 10 miles to send A very light thing, and classmate A has just finished sending it, the teacher asks him to send it again. Such repetition makes classmate A tired. Therefore, classmate A is smart, and the teacher asks him to send something. He doesn't rush to send it, but waits for almost everything to be given and sends it at one time. This improves efficiency.

#### Output file buffer

The output file buffer of Linux and Windows can output the contents of the buffer to the file by refreshing, closing the file and exiting the executable file. There is also a special case, that is, the output file buffer is full.

Next, verify the file buffer by closing the file and exiting the executable

```#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc,char *argv[])
{
char buf[] = "this is a test.\n";

//Define a file pointer
FILE* fp = fopen("./demo.text","w+");

fputs(buf,fp);

printf("\n");
system("pause");
return 0;
}
```

Note: the above program does not close the file because I did not write close(fp);
The program can be executed and will not be closed temporarily. View the demo in the local Txt file. The description is not written in.
Close the executable program or write close(fp) in the program; Try again, The instructions are written in.

Next, verify the file buffer by refreshing the function fflush

```#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc,char *argv[])
{
char buf[] = "this is a test.\n";

//Define a file pointer
FILE* fp = fopen("./hello.text","w+");

fputs(buf,fp);

fflush(fp);

printf("\n");
system("pause");
return 0;
}
```

Running program: The instructions are written in.

### Input / output stream    ## File pointer in C language ### File handle

A handle is actually a structure variable. ## File api

### Standard file reading and writing   Note:
1,
If the suffix is "w", if the file exists, the file content will be cleared first. Therefore, sometimes when you want to read or write a file, you use the "rw" parameter, but the final result is that the file content is emptied. Therefore, if you want to read and write files in the future, you can use "r +" so that the contents of the file will not be emptied.

2,
Using "rb" is to use binary files, while using "rt" is to open text files, and "t" can be omitted.

3,
On Windows Platforms,

After opening the text file,
When writing a file, it will automatically change "\ n" to "\ r\n",
When reading a file, it will automatically change "\ r\n" to "\ n"

Not on Linux. What you write is what you read. Therefore, the result of opening the same text file on windows may be different from that on Linux.

For binary files, after they are opened, no matter on Linux or windows platforms, they are written as they are and read as they are.

### Different types of read-write file APIs Keywords: OpenCV Qt Ubuntu

Added by RedRasper on Thu, 03 Mar 2022 15:10:56 +0200