Note: This blog is written word by word by the blogger, which is not easy. Please respect the originality, thank you all!
Scope
C
The scope of language variables is divided into:
- code block scope (a code block is a section of code between
{}
) - function scope
- file scope
1) Local variables
Life cycle: when to open up space (birth) and release space (death), this process is called life cycle.
Local variables are also called auto
automatic variables (auto
can be written or not), generally code blocks < a i=4>The internally defined variables are all automatic variables, which have the following characteristics:{}
- Scope: defined within a function, it is only valid within the function scope; defined in a compound statement, it is only valid within the compound statement
- Life cycle:The program runs to the variable definition to open up space. With the end of the function call or the end of the compound statement, the life cycle of the local variable also ends, and the space is released< /span>
- If no initial value is assigned, the content is random.
Example 1:
#include <stdio.h>
void test()
{
//auto写不写是一样的
//auto只能出现在{}内部
auto int b = 20;
return;
}
int main(){
//b = 100; //err, 在main作用域中没有b
//int c;
//printf("c=%d\n", c); // 未初始化的值 随机
int* p = NULL;
if (1)
{
//在复合语句中定义,只在复合语句中有效
int a = 10;
int d = 30;
p = &d;
printf("a = %d\n", a);
}
//a = 10; //err 离开if()的复合语句,a已经不存在
*p = 300;
printf("%d", *p);
return 0;
}
输出结果
a = 10
300
2) Static local variables
- Scope:
static
The scope of local variables is also valid within the defined function - Life cycle:
static
The life cycle of local variables is the same as the program running cycle. The space has been opened before the execution of themain
function. When the program ends to release space; at the same timestatic
the value of local variable is only initialized once, but can be assigned multiple times static
If a local variable is not assigned an initial value, it will be automatically assigned by the system: Numeric variables are automatically assigned an initial value0
, and character variables are assigned a null character
Example 1:
#include <stdio.h>
void fun1()
{
int num1 = 1;
num1++;
printf("num1 = %d\n", num1);
}
void fun2()
{
//静态局部变量,没有赋值,系统赋值为0,而且只会初始化一次
static int num2 = 1;
num2++;
printf("num2 = %d\n", num2);
}
int main(void)
{
static int n;
printf("n = %d\n", n); // n = 0
fun1(); // num1 = 2
fun1(); // num1 = 2
fun2(); // num2 = 2
fun2(); // num2 = 3
return 0;
}
输出结果
n = 0
num1 = 2
num1 = 2
num2 = 2
num2 = 3
3) Global variables
- Scope: defined outside the function, can be shared by functions in this file and other files (all files in the entire project). If functions in other files call this variable, they must use
extern
Statement - Life cycle: The life cycle of global variables is the same as the program running cycle. The space is opened before the main function is executed, and the space is released after the program ends.
- If a global variable is not assigned an initial value, it will be automatically assigned by the system: Numeric variables are automatically assigned an initial value
0
, and character variables are assigned a null character - Global variables in different files cannot have the same name.
Example 1:
#include <stdio.h>
int num;
void test01() {
num = 10;
printf("num = %d\n", num);
}
int main() {
printf("num = %d\n", num); // 0
test01(); // 10
return 0;
}
Example 2:
#include <stdio.h>
extern int num; // 声明num在其他文件定义过
int main() {
num = 100;
printf("num = %d\n", num);
return 0;
}
4) Static global variables
- Scope: defined outside the function, the scope is limited to the defined file (current file);Static global variables in different files can have the same name, but the scope does not Conflict
- Life cycle:
static
The life cycle of global variables is the same as the program running cycle. The space is opened before the main function is executed, and the space is released after the program ends; at the same time< a i=2>The value of the global variable is only initialized oncestaitc
static
If a global variable is not assigned an initial value, it will be automatically assigned by the system: Numeric variables are automatically assigned an initial value0
, and character variables are assigned a null character
Example 1:
#include <stdio.h>
static int num2;
void test02() {
num2 = 20;
printf("num2 = %d\n", num2);
}
int main() {
printf("num2 = %d\n", num2); // 0
test02(); // 20
return 0;
}
Example 2:
#include <stdio.h>
extern int num2; // error 静态全局变量不能进行声明,更不能在其他文件使用
int main() {
num2 = 100;
printf("num2 = %d\n", num2);
return 0;
}
Scope: Local variables (ordinary local and static local) are within the scope of{}
; ordinary global variables have scope in the entire project; static Globally affects the current file.
Life cycle: Only ordinary local variables are opened when running to the variable definition, and are released after the function ends. Other variables are executed before the main
function The space has been opened up and will not be released until the program ends.
Initialized value: Only ordinary local uninitialized values are random, others are0
.
5) The problem of dividing global variables into files
Defects of global variable redefinition in C language:
#include <stdio.h>
// 全局变量之所以能编译过去,是因为其中有三个默认为声明extern,因为extern可写可不写,所以最好声明加上 extern
int a;
int a;
int a;
int a;
int main() {
int b;
//int b; // error 重定义
return 0;
}
First, let’s look at the correct handling of global variables in files.
main.c
document
#include <stdio.h>
#include "demo.h"
// 声明全局变量cnum
//extern int cnum;
//extern void cfunc();
int main() {
cfunc();
printf("cnum = %d", cnum);
return 0;
}
demo.c
document
#include <stdio.h>
// 定义全局变量
int cnum=10;
void cfunc() {
cnum = 100;
}
demo.h
document
#pragma once
// 声明全局变量cnum
extern int cnum;
extern void cfunc();
Now comment out the declaration of global variables in the demo.h
header file and change it to int cnum;
. In this case, the compiler can compile it , when it is not known whether it is a definition or a declaration, and the existence of in the demo.c
file will be regarded as a definition, then in After in the function, it is equivalent to the presence of in the function. It will be treated as a statement, that is, no error will be reported during compilation. int cnum=10;
main
include "demo.h"
main
int cnum;
Then if you modify demo.h
in the header file int cnum;
to define int cnum=20;
, then an error will be reported for redefinition, so In the .h
file, global variables are only declared but not defined. The definition is only placed in the .c
file
6) The problem of variable name duplication
Taking into account the proximity principle under the premise of scope:
Example 1:
a.c
document
#include <stdio.h>
static char* language = "java";
void func3()
{
printf("language = %s\n", language);
}
b.c
document
#include <stdio.h>
// 不同作用域可以重名
char* language = "c";
func2()
{
printf("language = %s\n", language);
}
int main()
{
func2();
func3();
char* language = "c++";
printf("language = %s\n", language);
if (1)
{
char* language = "python";
printf("language = %s\n", language);
}
printf("language = %s\n", language);
return 0;
}
Example 2:
func1.c
document
int va = 7;
int getG(void)
{
int va = 20;
return va;
}
func2.c
document
static int va = 18;
static int getG(void)
{
return va;
}
int getO(void)
{
return getG();
}
main.c
document
#include <stdio.h>
extern int va;
extern int getG(void);
extern int getO(void);
int main()
{
printf("va=%d\n", va);
printf("getO=%d\n", getO());
printf("getG=%d\n", getG());
printf("%d", va*getO()*getG());
}
7) Global functions and static functions
In theC
language, functions are global by default. Use the keywordstatic
to declare the function as static, and the function is defined as static
means that this function can only be used in the file in which this function is defined, and cannot be called in other files. Even if this function is declared in other files, it will be useless.
- Ordinary functions without any modification are global functions that can be called by the entire project.
- A static function is a function that is modified with
static
when the function is defined. A static function can only be called by the current file function
Global functions:
#include <stdio.h>
static char* language = "java";
// 全局函数
void func3()
{
printf("language = %s\n", language);
}
Static function:
// 静态函数
static void func4()
{
printf("language = %s\n", language);
}
If you have to call a static function, you can define a global function in the .c file where the static function is located, and call the static function in the same file in this global function. Then we can call the static function by calling this global function.
// 静态函数
static void func4()
{
printf("language = %s\n", language);
}
// 全局函数
void func5()
{
// 调用静态函数
func4();
}
Notice:
- The same variable name is allowed to be used in different functions. They represent different objects and are allocated to different units without interfering with each other.
- In the same source file, global variables and local variables are allowed to have the same name. Within the scope of local variables, global variables have no effect.
- All functions are global by default, which means that all functions cannot have the same name, but if it is a
staitc
function, the scope is file level, so different filesstatic
The function names can be the same.
8) Summary
type | Scope | life cycle |
---|---|---|
auto variable |
Itshu{
} inside |
current function |
static local variables |
Itshu{} Inside |
The entire program running period |
extern variable |
the whole program | The entire program running period |
static global variables |
current file | The entire program running period |
extern function |
the whole program | The entire program running period |
static function |
current file | The entire program running period |
register variable |
Itshu{} Inside |
current function |
global variables | the whole program | The entire program running period |
memory layout
1) Memory partition
C
The code generates an executable program after four steps of preprocessing, compilation, assembly, and linking.
Under Windows
, the program is an ordinary executable file. The basic situation of a binary executable file is listed below:
As can be seen from the above figure, before the program is run, that is to saybefore the program is loaded into the memory, inside the executable program Three pieces of information have been divided into code area (text), data area (data) and uninitialized data area (bss) ( Some people directly call data
and bss
together as the static area or global area).
-
Code area
stores the machine instructions executed byCPU
. Usually the code area is shareable (that is, other executing programs can call it). The purpose of making it shareable is that for frequently executed programs, only one copy of the code is needed in the memory. A code area is usually read-only. The reason for making it read-only is to prevent the program from accidentally modifying its instructions. In addition, the code area also plans relevant information about local variables. -
Global initialization data area/static data area (data section)
This area contains global variables that are explicitly initialized in the program and initialized static variables (including global static variables and local static variables) and constant data (such as string constants). -
Uninitialized data area (also called bss area)
stores global uninitialized variables and uninitialized static variables. The data in the uninitialized data area is initialized by the kernel to0
or empty (NULL
) before the program starts executing.
Before the program is loaded into memory, the sizes of the code area and global area (data and bss) are fixed . It cannot be changed while the program is running. Then, run the executable program, and the system loads the program into the memory. In addition to dividing the code area (text), data area (data) and uninitialized data area (bss) according to the information of the executable program ), a stack area and a heap area are also added.
-
Code area (text segment)
loads the executable file code segment. All executable codes are loaded into the code area. This memory cannot be modified during operation. of. -
Uninitialized data area (BSS)
loads the executable fileBSS
section. The location can be separated or close to the data section. It is stored in The life cycle of the data in the data segment (global uninitialized, static uninitialized data) is the entire program running process. -
Global initialization data area/static data area (data segment)
The executable file data segment is loaded and stored in the data segment (global initialization, static initialization data, literal constants ( The data lifetime of read-only)) is the entire program running process. -
Stack area (stack)
The stack is a first-in, last-out memory structure that is automatically allocated and released by the compiler to store function parameter values, return values, local variables, etc. It is loaded and released in real time during the running of the program. Therefore, the life cycle of local variables is to apply for and release the stack space. -
Heap area (heap)
The heap is a large container. Its capacity is much larger than that of the stack, but it does not have the first-in, last-out order like the stack. Used for dynamic memory allocation. The heap is located between theBSS
area and the stack area in memory. Generally, it is allocated and released by the programmer. If the programmer does not release it, it will be recycled by the operating system when the program ends.
2) Summary of storage types
type | Scope | life cycle | storage location |
---|---|---|---|
auto variable |
Itshu{} Inside |
current function | stack area |
static local variables |
Itshu{} Inside |
The entire program running period | is initialized in the data section, uninitialized in the BSS section |
extern variable |
the whole program | The entire program running period | is initialized in the data section, uninitialized in the BSS section |
static global variables |
current file | The entire program running period | is initialized in the data section, uninitialized in the BSS section |
extern function |
the whole program | The entire program running period | code area |
static function |
current file | The entire program running period | code area |
register variable |
Itshu{} Inside |
current function | stored inCPU register during runtime |
String constant | current file | The entire program running period | data part |
Example:
#include <stdio.h>
#include <stdlib.h>
int e;
static int f;
int g = 10;
static int h = 10;
int main()
{
int a;
int b = 10;
static int c;
static int d = 10;
char *i = "test";
char *k = NULL;
printf("&a\t %p\t //局部未初始化变量\n", &a);
printf("&b\t %p\t //局部初始化变量\n", &b);
printf("&c\t %p\t //静态局部未初始化变量\n", &c);
printf("&d\t %p\t //静态局部初始化变量\n", &d);
printf("&e\t %p\t //全局未初始化变量\n", &e);
printf("&f\t %p\t //全局静态未初始化变量\n", &f);
printf("&g\t %p\t //全局初始化变量\n", &g);
printf("&h\t %p\t //全局静态初始化变量\n", &h);
printf("i\t %p\t //只读数据(文字常量区)\n", i);
k = (char *)malloc(10);
printf("k\t %p\t //动态分配的内存\n", k);
return 0;
}
输出结果
&a 003DFE9C //局部未初始化变量
&b 003DFE90 //局部初始化变量
&c 00088180 //静态局部未初始化变量
&d 00088014 //静态局部初始化变量
&e 000884A4 //全局未初始化变量
&f 0008817C //全局静态未初始化变量
&g 0008800C //全局初始化变量
&h 00088010 //全局静态初始化变量
i 00085060 //只读数据(文字常量区)
k 007104D0 //动态分配的内存
3) Memory operation function
3.1 memset()
Fill a memory space with a certain value:
- Header file:
#include <string.h>
- Define function:
void *memset(void *s, int c, size_t n);
- Function: Fill in the first bytes of the memory area of
s
with parametersn
c
- Parameter:
s:
The first address of the memory to be operated onThe characters filled in, Although the parameter is , it must be , and the range is Specify the size that needs to be sets
c:
c
int
unsigned char
0~255
n:
- Return value:The first address of
s
Example:
#include <stdio.h>
#include <string.h>
// memset函数
int main()
{
int a = 10;
//a = 0; -> memset()
memset(&a, 0, sizeof(a));
printf("a=%d\n", a);
char str[20] = "hellocdtaogang";
printf("str=[%s]\n", str);
memset(str, 0, sizeof(str));
printf("str=[%s]\n", str);
// 将前10个字符置为a字符
memset(str, 'a', sizeof(str) - 10); // memset(str, 97, sizeof(str) - 10);
printf("str=[%s]\n", str);
return 0;
}
输出结果
a=0
str=[hellocdtaogang]
str=[]
str=[aaaaaaaaaa]
3.2 memcpy()
Copy memory contents
- Header file:
#include <string.h>
- Define function:
void *memcpy(void *dest, const void *src, size_t n);
- Function: Copy the first bytes of the memory pointed to by
src
to the memory pointed by on the address.n
dest
- Parameters:
dest:
First address of destination memory
src:
First address of source memory,Note:< The memory spaces pointed to by a i=4> and cannot overlap, which may cause the program to report an error. Number of bytes to be copieddest
src
n:
- Return value:The first address of
dest
Example:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
// memcpy函数
int main()
{
int a[10] = {
1,2,3,4,5,6,7,8,9,10 };
int b[10] = {
0 };
// a = b;// error 常量不能修改
// 将a数组中的前五个元素拷贝到b数组中
memcpy(b, a, sizeof(int)*5);
for (int i = 0; i < sizeof(b)/sizeof(b[0]); i++)
{
printf("%d ", b[i]);
}
printf("\n");
char str1[128] = "";
char str2[128] = "abc\0def\0hellocdtaogang";
char str3[128] = "";
// 使用strncpy
strncpy(str1, str2, sizeof(char) * 22);
for (int i = 0; i < 22; i++)
{
printf("%d ", str1[i]);
}
printf("\n");
// 使用memcpy
memcpy(str3, str2, sizeof(char) * 22);
for (int i = 0; i < 22; i++)
{
printf("%d ", str3[i]);
}
return 0;
}
输出结果
1 2 3 4 5 0 0 0 0 0
97 98 99 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
97 98 99 0 100 101 102 0 104 101 108 108 111 99 100 116 97 111 103 97 110 103
3.3 memmove()
memmove()
The function usage is the same as memcpy()
, the difference is: when the memory spaces pointed to by dest
and src
overlap, < /span>. memmove()
can still be processed, but the execution efficiency is lower than memcpy()
3.4 memcmp()
Compare memory contents
- Header file:
#include <string.h>
- Define function:
int memcmp(const void *s1, const void *s2, size_t n);
- Function: Compare the first bytes of the memory area pointed to by
s1
ands2
n
- Parameters:
s1:
Memory first address 1
s2:
Memory first address 2
n:
The first n bytes to be compared - Reply:
Equal:=0
Dayu:>0
Xiaoyu:<0
Example:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
// memcmp函数
int main()
{
int a[10] = {
1, 0, 2, 3, 5, 6, 2, 8, 9, 10 };
int b[10] = {
1, 0, 4, 4, 5, 6, 7, 8, 9, 10 };
int res1 = memcmp(a, b, sizeof(int));
printf("res1 = %d\n", res1);
int res2 = memcmp(a, b, sizeof(int)*10);
printf("res2 = %d\n", res2);
int res3 = strncmp(a, b, sizeof(int) * 10); // strncmp遇到0就结束了
printf("res3 = %d\n", res3);
char str1[] = "abcd\0abc";
char str2[] = "abcd\0bbc";
printf("%d\n", strncmp(str1, str2, sizeof(str1))); // strncmp遇到\0就结束了
printf("%d\n", memcmp(str1, str2, sizeof(str1)));
return 0;
}
输出结果
res1 = 0
res2 = -1
res3 = 0
0
-1
4) Heap area memory allocation and release
4.1 malloc()
Configure memory space
- Header file:
#include <stdlib.h>
- Define function:
void *malloc(size_t size);
- Function: Allocate a continuous area of size bytes in the dynamic storage area (heap area) of the memory to store the type specified by the type specifier. The content of the allocated memory space is uncertain and is generally initialized using
memset
. - Parameters:
size
: Memory size to be allocated (unit: bytes) - Return value:
Success: starting address of allocated space
Failure:NULL
Example:
#include <stdio.h>
#include <stdlib.h>
// malloc函数
int main()
{
//int a[10]; 直接是从栈区申请空间
//申请一个数组,数组有10个元素,每个元素int类型,到堆区申请内存空间
int* p = (int *)malloc(sizeof(int) * 10); // malloc函数的返回值未void *类型最好是强转下
*p = 100;
*(p + 5) = 200;
for (int i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
}
输出结果
100 -842150451 -842150451 -842150451 -842150451 200 -842150451 -842150451 -842150451 -842150451
4.2 free()
Release the originally configured memory
- Header file:
#include <stdlib.h>
- Define function:
void free(void *ptr);
- Function: Release a memory space pointed to by
ptr
.ptr
is a pointer variable of any type, pointing to the first address of the released area. Freeing the same memory space multiple times will cause an error. - Parameters:
ptr:
The first address of the space to be released. The released area should be the area allocated by themalloc
function.
Return value: None
Example:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// free函数
int main()
{
//申请一个字符数组,有1024元素
char* p = (char *)malloc(1024);
//将申请到空间清0
memset(p, 0, 1024);
strcpy(p, "hellocdtaogang");
// 释放内存
free(p);
//free(p+1) // free 参数 地址必须是上一次malloc申请过的,不能去改变这个地址
//printf("%s\n", p); // 释放完了再打印那么就不会是你想要的数据
//free(p); // malloc申请的空间不可以释放两次,申请一次,释放一次
return 0;
}
Note:free
The space applied for last time can only be released once;free
The parameter address must be the last onemalloc
If you have applied, you cannot change this address;malloc
The applied space cannot be released twice. Apply once and release once.
4.3 Memory leak
Memory leak: only apply for but not release
Memory pollution: write data to unapplied memory space
Memory partition code analysis
1) Return stack area address
Example:Ordinary local variables exist in the stack area and will be released when the function call is completed, so the address of ordinary local variables cannot be returned for operation.
#include <stdio.h>
int* newfunc()
{
int a = 10;
a *= 10;
return &a; // 函数调用完毕,a释放
}
int main()
{
int* p = newfunc();
//操作野指针指向的内存
*p = 200; // error p所指向的空间已经被释放,
printf("%d\n", *p);
return 0;
}
2) Return the data area address
Example 1:Static local variables exist in the static global area, and initialized ones exist in the data area. As long as the program does not exit, they will not be released, so the addresses of these variables can be returned. operate.
#include <stdio.h>
int* newfunc()
{
//int a = 10;
static int a = 10;
a *= 10;
return &a;
}
int main()
{
int* p = newfunc();
*p = 200; // p所指向的空间没有释放(静态局部变量),则可以操作这块内存
printf("%d\n", *p);
return 0;
}
Example 2:Static global and global variables exist in the static global area, and initialized ones exist in the data area. As long as the program does not exit, they will not be released, so the addresses of these variables are Operation can be returned.
#include <stdio.h>
//int a = 10; // 全局变量变量
static int a = 10; // 静态全局变量
int* newfunc()
{
//int a = 10;
//static int a = 10;
a *= 10;
return &a;
}
int main()
{
int* p = newfunc();
*p = 200; // p所指向的空间没有释放(静态全局变量、全局变量),则可以操作这块内存
printf("%d\n", *p);
return 0;
}
In short:Only the address of ordinary local variables cannot be returned, because ordinary local variables are released after the function ends; while static local variables, global variables, and static global variables These variables will not be released as long as the program does not exit, so the addresses of these variables can be returned to the operation.
3) Value transfer
Example 1:The essence of the formal parameter is a local variable. When the function call is completed, it will be released, so the address of the formal parameter cannot be returned.
#include <stdio.h>
int* newfunc2(int num)
{
//形参的本质就是局部变量
num += 100;
return # // 函数调用完毕,num释放,不可以返回形参的地址
}
int main()
{
int num = 10;
int *p = newfunc2(num);
*p = 200;
return 0;
}
Example 2:Define the function to return the address of k actual parameters, so the actual parameter address will not be released when the function ends.
#include <stdio.h>
int* newfunc3(int *k)
{
int i = 100;
*k = *k + i;
return k; // 返回k指向的num的地址,所以函数结束num变量的地址没有被释放
}
int main()
{
int num = 10;
int* p = newfunc3(&num);
return 0;
}
Example 3:
4) Return the heap area address
Example:The address of the heap area can be returned, and the heap area will not be released after the function ends; however, string constants cannot be assigned directly, which will cause space loss and memory loss. leak
#include <stdio.h>
#include <stdlib.h>
char* newfunc4()
{
char* q = malloc(100);
return q; // 堆区的地址是可以返回的,函数结束不会被释放
}
int main()
{
char* p = newfunc4();
p = "hello";
free(p); // error p并没有指向堆区,而是指向文字常量区"hello"
return 0;
}
Assignp
to an integer, and there will be no error
Usingstrcpy(p, "hello");
will not cause memory leaks
5) The actual parameter is the address of the first-level pointer
Example 1: Passing by value of the function cannot change the value of the actual parameter
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void mem_p(char *q)
{
q = malloc(1024);
return;
}
int main()
{
char* p = NULL;
mem_p(p);
strcpy(p, "hello");
printf("p=%s\n", p);
return 0;
}
If you compile and run directly, no error will be reported, but no data will be printed. It can only be said that the compiler does not prompt an error, but the error can be viewed through break points.
causes the above error because p
points to NULL
and does not point to the heap address, causing memory pollution. The solution is p
just points to the address opened in the heap area.
char* mem_p(char *q)
{
q = malloc(1024);
return q;
}
int main()
{
char* p = NULL;
p = mem_p(p);
strcpy(p, "hello");
printf("p=%s\n", p);
return 0;
}
Example 2: Pass the address of the actual parameter, and you can change the value of the actual parameter when calling the function (the actual parameter is the first-level pointer address, and the formal parameter is the second-level pointer)
void mem_p2(char** k)
{
*k = malloc(1024);
return;
}
int main()
{
char* p = NULL;
mem_p2(&p);
strcpy(p, "hello");
printf("p=%s\n", p);
return 0;
}