前言

学习指的目的,有一点来头了且有一点绕。

我本是在做数值分析中矩阵行列式的MATLAB代码,但是之前C程序设计的课程报告里面已经把矩阵运算的各种代码编写的十分的完善。但是我在复现之中,想把动态开辟内存的C++方法new替换成C中的malloc进行动态开辟。但是自己搞了很久也没有搞懂如何动态开辟空间,所以就跟指针干上了。

下面是B站的课程:C指针视频教程

以及CSDN上面的博客总结了这个视频:视频知识点总结

C结构体视频教程

下面开始总结复习~

指针的基本概念

1
2
3
4
5
6
7
8
9
int a = 4;
int* p;//指针的声明
p = &a;//取地址

printf("p指向的地址为%d \n", p);
printf("p所指向的值为%d \n", *p);//解引用
printf("a的地址为%d \n", &a);
printf("a的值为%d \n", a);

1
2
3
4
5
p指向的地址为5700172
p所指向的值为4
a的地址为5700172
a的值为4

注:p指向的地址与a的地址在每一次编译时都不一样

值的修改

1
2
3
4
5
6
7
8
9
10
int a;
int* p;

a = 10;
p = &a;
printf("a的值为%d \n", a);

*p = 12;
printf("a的值为%d \n", a);

1
2
3
a的值为10
a的值为12

1
2
3
4
5
6
7
8
9
10
11
12
int a;
int* p;
a = 10;
p = &a;
printf("p指向的地址为%d \n", p);
printf("p所指向的值为%d \n", *p);

int b = 20;
*p = b;
printf("p指向的地址为%d \n", p);
printf("p所指向的值为%d \n", *p);

1
2
3
4
5
p指向的地址为10353004
p所指向的值为10
p指向的地址为10353004
p所指向的值为20

注:地址未发生变化,只有值进行了改变

指针的+1

1
2
3
4
5
6
7
8
9
10
11
12
13
int a;
int* p;
a = 10;
p = &a;

printf("p指向的地址为%d \n", p);
printf("p所指向的值为%d \n", *p);
printf("int的大小为%d 个字节\n", sizeof(int));
printf("p+1指向的地址为%d \n", p + 1);
printf("p+1所指向的值为%d \n", *(p + 1));
printf("p+2指向的地址为%d \n", p + 2);
printf("p+2所指向的值为%d \n", *(p + 2));

1
2
3
4
5
6
7
8
p指向的地址为11728720
p所指向的值为10
int的大小为4 个字节
p+1指向的地址为11728724
p+1所指向的值为-858993460
p+2指向的地址为11728728
p+2所指向的值为-1790077520

注:指针 p 是一个指向整型变量的指针,而一个整型变量在内存中占4个字节, 对 p 执行加1,应该得到的是下一个整型数据的地址,即在地址的数值上面应该加4

指针的类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int a = 1025;
int* p;
p = &a;
printf("int的大小为%d 个字节\n", sizeof(int));
printf("p\t 指向的地址为%d, p所指向的值为%d\n", p, *p);
printf("p+1\t 指向的地址为%d, p所指向的值为%d\n", p + 1, *(p + 1));

char* p0;
p0 = (char*)p; // 强制类型转换

printf("char的大小为%d 个字节\n", sizeof(char));
printf("p0\t 指向的地址为%d, p0所指向的值为%d\n", p0, *p0);
printf("p0+1\t 指向的地址为%d, p0所指向的值为%d\n", p0 + 1, *(p0 + 1));

1
2
3
4
5
6
7
int的大小为4 个字节
p 指向的地址为15989384, p所指向的值为1025
p+1 指向的地址为15989388, p所指向的值为-858993460
char的大小为1 个字节
p0 指向的地址为15989384, p0所指向的值为1
p0+1 指向的地址为15989385, p0所指向的值为4

注:二进制1025 == 00000000 00000000 00000100 00000001

在字符中只有一个字节,机器看见00000001认为是1,看见第二个字节00000100认为是4

void指针

  • void*时通用指针类型,它不针对某个特定的指针类型。在使用时将其赋值为指向某种特定的数据类型的指针时不需要做强制类型转换。

  • 由于不知道它指向的类型,因此不能直接对其进行解引用*p,也不能对其进行算数运算p+1

1
2
3
4
5
6
7
8
9
10
int a = 1025;
int* p;
p = &a;
printf("int的大小为%d个字节\n", sizeof(int));
printf("p指向的地址为%d, p所指向的值为%d\n", p, *p);

void* p0;
p0 = p;
printf("p0指向的地址为%d \n", p0);

1
2
3
4
int的大小为4个字节
p指向的地址为14613824, p所指向的值为1025
p0指向的地址为14613824

指针的指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int x;
int* p;
p = &x;
*p = 6;
int** q = &p;
int*** r = &q;

printf("p指向的地址为%d, p所指向的值为%d\n", p, *p);
printf("q指向的地址为%d, q所指向的值为%d\n", q, *q);
printf("%d\n", **q);
printf("r指向的地址为%d, r所指向的值为%d\n", r, *r);
printf("%d\n", **r);
printf("%d\n", ***r);

***r = 10;
printf("\n修改过后,x的值为%d\n", x);

**q = *p + 2;
printf("\n修改过后,x的值为%d\n", x);

1
2
3
4
5
6
7
8
9
10
11
p指向的地址为6487408, p所指向的值为6
q指向的地址为6487396, q所指向的值为6487408
6
r指向的地址为6487384, r所指向的值为6487396
6487408
6

修改过后,x的值为10

修改过后,x的值为12

注:x是整型变量,p指向xq指向pr指向q

指针的指针描述

内存四区

  • 堆区(heap):一般由程序员手动分配释放(动态内存申请与释放),若程序员不释放,程序结束时可能由操作系统回收。

  • 栈区(stack):由编译器自动分配释放,存放函数的形参、局部变量等。当函数执行完毕时自动释放。

  • 全局区(global / stack):用于存放全局变量和静态变量, 里面细分有一个常量区,一些常量存放在此。该区域是在程序结束后由操作系统释放。

  • 代码区(code / text):用于存放程序代码,字符串常量也存放于此。

内存四区

函数传值

值传递call by value

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void Increment(int a)
{
a = a + 1;
printf("a在Increment子函数中的地址为%d\n", &a);
}

int main()
{
int a;
a = 10;
printf("经过Increment子函数前,a = %d\n", a);
Increment(a);
printf("经过Increment子函数后,a = %d\n", a);
printf("a在main函数中的地址为%d\n", &a);

return 0;
}

1
2
3
4
5
经过Increment子函数前,a = 10
a在Increment子函数中的地址为12252908
经过Increment子函数后,a = 10
a在main函数中的地址为12253120

注:在两个函数中操作的a变量并不是同一个,所以程序输出的是没有加1过的a的值。

Increment()函数中,临时变量local variable a,会在该函数结束后立刻释放掉。也就是说Increment()函数中的a ,和main() 函数中的 a 并不是同一个变量。

传引用 call by reference

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void Increment(int* p)
{
*p = *p + 1;
printf("a在Increment子函数中的地址为%d\n", p);
}

int main()
{
int a;
a = 10;
printf("经过Increment子函数前,a = %d\n", a);
Increment(&a);
printf("经过Increment子函数后,a = %d\n", a);
printf("a在main函数中的地址为%d\n", &a);

return 0;
}

1
2
3
4
5
经过Increment子函数前,a = 10
a在Increment子函数中的地址为16645096
经过Increment子函数后,a = 11
a在main函数中的地址为16645096

数组与指针

数组运算

1
2
3
4
5
6
int A[] = { 2,4,6,8,1 };
printf("A的地址为%d\n", A);
printf("A[0]的地址为%d\n", &A[0]);
printf("A[0]的值为%d\n", A[0]);
printf("A地址的值为为%d\n", *A);

1
2
3
4
5
A的地址为10221948
A[0]的地址为10221948
A[0]的值为2
A地址的值为为2

1
2
3
4
5
6
7
8
9
10
11
int A[] = { 2,4,6,8,1 };
int* p = A;
printf("p的地址为%d,p所指向的值为%d\n", p, *p);

for (int i = 0; i < 5; i++)
{
printf("A+%d的地址为%d,A+%d地址的值为为%d\n", i, A + i, i, *(A + i));
printf("A[i]的地址为%d,A[i]的值为%d\n", &A[i], A[i]);
printf("p+%d地址的值为为%d,p+%d所指向的值为%d\n\n", i, p + i, i, *(p + i));
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
p的地址为15726436,p所指向的值为2
A+0的地址为15726436,A+0地址的值为为2
A[i]的地址为15726436,A[i]的值为2
p+0地址的值为为15726436,p+0所指向的值为2

A+1的地址为15726440,A+1地址的值为为4
A[i]的地址为15726440,A[i]的值为4
p+1地址的值为为15726440,p+1所指向的值为4

A+2的地址为15726444,A+2地址的值为为6
A[i]的地址为15726444,A[i]的值为6
p+2地址的值为为15726444,p+2所指向的值为6

A+3的地址为15726448,A+3地址的值为为8
A[i]的地址为15726448,A[i]的值为8
p+3地址的值为为15726448,p+3所指向的值为8

A+4的地址为15726452,A+4地址的值为为1
A[i]的地址为15726452,A[i]的值为1
p+4地址的值为为15726452,p+4所指向的值为1

对于第i个元素:

  • 取地址:&A[i] or (A+i)

  • 取值: A[i] or *(A+i)

注:数组名不能直接自加,即不可~~A++~~,但是可以将其赋值给一个指针,指针可以自加:p++

常量不能被赋值,即若有数组名 A,指针 p,则~~A = p~~是非法的

数组参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int SumOfElements(int A[], int size)
{
int i, sum = 0;
for (i = 0; i < size; i++) {
sum += A[i];
}
return sum;
}

int main() {
int A[] = { 1, 2, 3, 4, 5 };
int size = sizeof(A) / sizeof(A[0]);
int total = SumOfElements(A, size);
printf("数组元素之和为%d\n", total);

return 0;
}

1
2
数组元素之和为15

进一步的封装,将数组元素个数的计算也放到调用函数内来进行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int SumOfElements(int A[])
{
int i, sum = 0;
int size = sizeof(A) / sizeof(A[0]);
printf("SOE函数 - A的大小为%d, A[0]的大小为%d\n", sizeof(A), sizeof(A[0]));
for (i = 0; i < size; i++) {
sum += A[i];
}
return sum;
}


int main()
{
int A[] = { 1, 2, 3, 4, 5 };
printf("Main函数 - A的大小为%d, A[0]的大小为%d\n", sizeof(A), sizeof(A[0]));
int total = SumOfElements(A);
printf("数组元素之和为%d\n", total);

return 0;
}

1
2
3
4
Main函数 - A的大小为20, A[0]的大小为4
SOE函数 - A的大小为4, A[0]的大小为4
数组元素之和为1

实际上,编译器只把数组A的首地址赋值给一个指针,作为SOE()的形参。

子函数SumOfElements(int A[])其实是相当于SumOfElements(int* A)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int SumOfElements(int* A)//这里有改动
{
int i, sum = 0;
int size = sizeof(A) / sizeof(A[0]);
printf("SOE函数 - A的大小为%d, A[0]的大小为%d\n", sizeof(A), sizeof(A[0]));
for (i = 0; i < size; i++) {
sum += A[i];
}
return sum;
}


int main()
{
int A[] = { 1, 2, 3, 4, 5 };
printf("Main函数 - A的大小为%d, A[0]的大小为%d\n", sizeof(A), sizeof(A[0]));
int total = SumOfElements(A);
printf("数组元素之和为%d\n", total);

return 0;
}

数组作为函数参数时是传引用(call by reference),而非我们预期的值传递。传引用的指针A可以改为&A[0]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int SumOfElements(int* A, int size)
{
int i, sum = 0;
printf("SOE函数 - A的大小为%d, A[0]的大小为%d\n", sizeof(A), sizeof(A[0]));
for (i = 0; i < size; i++) {
sum += A[i];
}
return sum;
}


int main()
{
int A[] = { 1, 2, 3, 4, 5 };
int size = sizeof(A) / sizeof(A[0]);
printf("Main函数 - A的大小为%d, A[0]的大小为%d\n", sizeof(A), sizeof(A[0]));
int total = SumOfElements(&A[0], size);//这里有改动
printf("数组元素之和为%d\n", total);

return 0;
}

通常来讲,数组会是一个很长,占内存空间很大的变量,如果每次传参都按照值传递完整地拷贝一份的话,效率极其低下。而如果采用传引用的方式,需要传递的只有一个指针的大小。

字符数组

字符数组

1
2
3
4
5
6
7
char C[4];
C[0] = 'J';
C[1] = 'O';
C[2] = 'H';
C[3] = 'N';
printf("%s", C);

1
JOHN烫烫槴瘌?

测试得到的输出结果是JOHN+几个乱码,因为没有设置 \0 来标识字符串的结束。

1
2
3
4
5
6
7
8
9
char C[4];
C[0] = 'J';
C[1] = 'O';
C[2] = 'H';
C[3] = 'N';
C[4] = '\0';

printf("%s", C);

1
JOHN

通过在字符数组的最后添加一个 \0 来标志字符串的结束,所以字符数组的长度要比字符串中字符的个数至少多一个

通过引入头文件string.h,可以使用strlen()函数获取到字符串的长度,无论我们声明的字符数组有多长(比如20),该函数会找到第一个 \0,并返回之前的元素个数,也就是我们实际的字符串长度。

1
2
3
4
5
6
7
8
9
10
char C[20];
C[0] = 'J';
C[1] = 'O';
C[2] = 'H';
C[3] = 'N';
C[4] = '\0';

int len = strlen(C);
printf("数组%s的长度为%d", C, len);

1
数组JOHN的长度为4

通过 char C[20] = "JOHN" 这种方式定义的字符串,**编译器一定会在其末尾添加一个 **\0

1
2
3
4
5
6
char C[20] = "JOHN";

int len = strlen(C);
printf("数组%s的长度为%d", C, len);
printf("数组%s的长度字节数为%d", C, sizeof(C));

1
2
数组JOHN的长度为4
数组JOHN的长度字节数为20

也可以不指定数组的大小,把char C[20] = "JOHN"改成char C[] = "JOHN"

1
2
3
4
5
6
char C[] = "JOHN";

int len = strlen(C);
printf("数组%s的长度为%d", C, len);
printf("数组%s的长度字节数为%d", C, sizeof(C));

1
2
数组JOHN的长度为4
数组JOHN的长度字节数为5

显示指定数组,把char C[20] = "JOHN"改成char C[5] = {'J','O','H','N','\0'};"

1
2
3
4
5
6
char C[5] = {'J','O','H','N','\0'};

int len = strlen(C);
printf("数组%s的长度为%d", C, len);
printf("数组%s的长度字节数为%d", C, sizeof(C));

1
2
数组JOHN的长度为4
数组JOHN的长度字节数为5

编写输出子函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void printString(char* C)
{
int i = 0;
while (C[i] != '\0') {
printf("%c", C[i]);
i++;
}
printf("\n");
}


int main()
{
char C[20] = "Hello";
printString(C);

return 0;
}

1
Hello

可以将C[i]替换成*(C + i)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void printString(char* C)
{
int i = 0;
while (*(C + i) != '\0') {
printf("%c", *(C + i));
i++;
}
printf("\n");
}


int main()
{
char C[20] = "Hello";
printString(C);

return 0;
}

1
Hello

在子函数printString中,这里C代表指向字符型的指针,C++等于C = C + 1,即地址的值+1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void printString(char* C)
{
while (*C != '\0') {
printf("%c", *C);
C++;
}
printf("\n");
}

int main()
{
char C[20] = "Hello";
printString(C);

return 0;
}

1
Hello

字符串常量const char* C = "Hello";,存放在代码区,其值不能被修改。~~C[0] = ‘A’~~是非法操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void printString(const char* C)
{
while (*C != '\0') {
printf("%c", *C);
C++;
}
printf("\n");
}

int main()
{
const char* C = "Hello";
printString(C);

return 0;
}

1
Hello

二维数组

二维数组

二维数组:int B[2][3]

B[0], B[1] 都是包含3个整型数据的一维数组

B返回的不是一个整型变量,而是一个包含3个整型变量的一维数组。~~int* p = B~~是非法的,应该写int (*p)[3] = B

*B返回一个指向整型的指针,int* q = *B是合法的

  • B是二维数组的数组名,亦为二维数组的首地址

  • *B是一维数组的首地址

  • B[0]是一维数组名,亦为一维数组首地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
int B[2][3] = { {2, 3, 6}, {4, 5, 8} };

printf("B的大小为%d,*B的大小为%d,B[0]的大小为%d,**B的大小为%d\n\n", sizeof(B), sizeof(*B), sizeof(B[0]), sizeof(**B));

printf("B的地址为%d,&B[0]的地址为%d\n", B, &B[0]);
printf("B+1的地址为%d,&B[1]的地址为%d\n\n", B + 1, &B[1]);

int(*p)[3] = B;
printf("p的地址为%d,p+1的地址为%d\n\n", p, p + 1);

int* q = *B;
for (int i = 0; i < 3; i++)
{
printf("q+%d的地址为%d,q+%d指向的值为%d\n", i, q + i, i, *(q + i));
}

for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
printf("*(B+%d)+%d地址的值为%d,", i, j, *(B + i) + j);
printf("B[%d]+%d的值为%d,", i, j, B[i] + j);
printf("B[%d][%d]的地址为%d\n", i, j, &B[i][j]);
printf("*(*(B+%d)+%d)的值为%d,", i, j, *(*(B + i) + j));
printf("*(B[%d]+%d)的值为%d,", i, j, *(B[i] + j));
printf("B[%d][%d]的值为%d\n", i, j, B[i][j]);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
B的大小为24,*B的大小为12,B[0]的大小为12,**B的大小为4

B的地址为2096816,&B[0]的地址为2096816
B+1的地址为2096828,&B[1]的地址为2096828

p的地址为2096816,p+1的地址为2096828

q+0的地址为2096816,q+0指向的值为2
q+1的地址为2096820,q+1指向的值为3
q+2的地址为2096824,q+2指向的值为6
*(B+0)+0地址的值为2096816,B[0]+0的值为2096816,B[0][0]的地址为2096816
*(*(B+0)+0)的值为2,*(B[0]+0)的值为2,B[0][0]的值为2
*(B+0)+1地址的值为2096820,B[0]+1的值为2096820,B[0][1]的地址为2096820
*(*(B+0)+1)的值为3,*(B[0]+1)的值为3,B[0][1]的值为3
*(B+0)+2地址的值为2096824,B[0]+2的值为2096824,B[0][2]的地址为2096824
*(*(B+0)+2)的值为6,*(B[0]+2)的值为6,B[0][2]的值为6
*(B+1)+0地址的值为2096828,B[1]+0的值为2096828,B[1][0]的地址为2096828
*(*(B+1)+0)的值为4,*(B[1]+0)的值为4,B[1][0]的值为4
*(B+1)+1地址的值为2096832,B[1]+1的值为2096832,B[1][1]的地址为2096832
*(*(B+1)+1)的值为5,*(B[1]+1)的值为5,B[1][1]的值为5
*(B+1)+2地址的值为2096836,B[1]+2的值为2096836,B[1][2]的地址为2096836
*(*(B+1)+2)的值为8,*(B[1]+2)的值为8,B[1][2]的值为8

转换公式:B[i][j] == *(B[i]+j) == *(*(B+i)+j)

多维数组

三维数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
int C[3][2][2] = { { {2,5},{7,9} },{ {3,4},{6,1} },{ {0,8},{11,13} } };

printf("C的大小为%d\n", sizeof(C));
printf("*C的大小为%d,C[0]的大小为%d\n", sizeof(*C), sizeof(C[0]));
printf("**C的大小为%d,C[0][0]的大小为%d,*C[0]的大小为%d\n", sizeof(**C), sizeof(C[0][0]), sizeof(*C[0]));
printf("***C的大小为%d,*C[0][0]的大小为%d,**C[0]的大小为%d,C[0][0][0]的大小为%d\n\n", sizeof(***C), sizeof(*C[0][0]), sizeof(**C[0]), sizeof(C[0][0][0]));

printf("C的地址为%d,*C地址的值为%d,C[0]地址的值为%d,C[0][0]地址为%d\n\n", C, *C, C[0], &C[0][0]);

int(*p)[2][2] = C;
for (int i = 0; i < 3; i++)
{
printf("p+%d的地址为%d\n", i, *(p + i));
}

int(*q)[2] = *C;
for (int i = 0; i < 2; i++)
{
printf("q+%d的地址为%d\n", i, *(q + i));
}

int* r = **C;
for (int i = 0; i < 2; i++)
{
printf("r+%d的地址为%d,r+%d指向的值为%d\n", i, r + i, i, *(r + i));
}

for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 2; k++)
{
printf("*(*(C+%d)+%d)+%d地址的值为%d,", i, j, k, *(*(C + i) + j) + k);
printf("*(C[%d]+%d)+%d的值为%d,", i, j, k, *(C[i] + j)) + k;
printf("C[%d][%d]+%d的值为%d,", i, j, k, C[i][j] + k);
printf("C[%d][%d][%d]的地址为%d\n", i, j, k, &C[i][j][k]);
printf("*(*(*(C+%d)+%d)+%d)的值为%d,", i, j, k, *(*(*(C + i) + j) + k));
printf("*(*(C[%d]+%d)+%d)的值为%d,", i, j, k, *(*(C[i] + j) + k));
printf("*(C[%d][%d]+%d)的值为%d", i, j, k, *(C[i][j] + k));
printf("C[%d][%d][%d]的值为%d\n", i, j, k, C[i][j][k]);
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
C的大小为48
*C的大小为16,C[0]的大小为16
**C的大小为8,C[0][0]的大小为8,*C[0]的大小为8
***C的大小为4,*C[0][0]的大小为4,**C[0]的大小为4,C[0][0][0]的大小为4

C的地址为7797352,*C地址的值为7797352,C[0]地址的值为7797352,C[0][0]地址为7797352

p+0的地址为7797352
p+1的地址为7797368
p+2的地址为7797384
q+0的地址为7797352
q+1的地址为7797360
r+0的地址为7797352,r+0指向的值为2
r+1的地址为7797356,r+1指向的值为5
*(*(C+0)+0)+0地址的值为7797352,*(C[0]+0)+0的值为7797352,C[0][0]+0的值为7797352,C[0][0][0]的地址为7797352
*(*(*(C+0)+0)+0)的值为2,*(*(C[0]+0)+0)的值为2,*(C[0][0]+0)的值为2C[0][0][0]的值为2
*(*(C+0)+0)+1地址的值为7797356,*(C[0]+0)+1的值为7797352,C[0][0]+1的值为7797356,C[0][0][1]的地址为7797356
*(*(*(C+0)+0)+1)的值为5,*(*(C[0]+0)+1)的值为5,*(C[0][0]+1)的值为5C[0][0][1]的值为5
*(*(C+0)+1)+0地址的值为7797360,*(C[0]+1)+0的值为7797360,C[0][1]+0的值为7797360,C[0][1][0]的地址为7797360
*(*(*(C+0)+1)+0)的值为7,*(*(C[0]+1)+0)的值为7,*(C[0][1]+0)的值为7C[0][1][0]的值为7
*(*(C+0)+1)+1地址的值为7797364,*(C[0]+1)+1的值为7797360,C[0][1]+1的值为7797364,C[0][1][1]的地址为7797364
*(*(*(C+0)+1)+1)的值为9,*(*(C[0]+1)+1)的值为9,*(C[0][1]+1)的值为9C[0][1][1]的值为9
*(*(C+1)+0)+0地址的值为7797368,*(C[1]+0)+0的值为7797368,C[1][0]+0的值为7797368,C[1][0][0]的地址为7797368
*(*(*(C+1)+0)+0)的值为3,*(*(C[1]+0)+0)的值为3,*(C[1][0]+0)的值为3C[1][0][0]的值为3
*(*(C+1)+0)+1地址的值为7797372,*(C[1]+0)+1的值为7797368,C[1][0]+1的值为7797372,C[1][0][1]的地址为7797372
*(*(*(C+1)+0)+1)的值为4,*(*(C[1]+0)+1)的值为4,*(C[1][0]+1)的值为4C[1][0][1]的值为4
*(*(C+1)+1)+0地址的值为7797376,*(C[1]+1)+0的值为7797376,C[1][1]+0的值为7797376,C[1][1][0]的地址为7797376
*(*(*(C+1)+1)+0)的值为6,*(*(C[1]+1)+0)的值为6,*(C[1][1]+0)的值为6C[1][1][0]的值为6
*(*(C+1)+1)+1地址的值为7797380,*(C[1]+1)+1的值为7797376,C[1][1]+1的值为7797380,C[1][1][1]的地址为7797380
*(*(*(C+1)+1)+1)的值为1,*(*(C[1]+1)+1)的值为1,*(C[1][1]+1)的值为1C[1][1][1]的值为1
*(*(C+2)+0)+0地址的值为7797384,*(C[2]+0)+0的值为7797384,C[2][0]+0的值为7797384,C[2][0][0]的地址为7797384
*(*(*(C+2)+0)+0)的值为0,*(*(C[2]+0)+0)的值为0,*(C[2][0]+0)的值为0C[2][0][0]的值为0
*(*(C+2)+0)+1地址的值为7797388,*(C[2]+0)+1的值为7797384,C[2][0]+1的值为7797388,C[2][0][1]的地址为7797388
*(*(*(C+2)+0)+1)的值为8,*(*(C[2]+0)+1)的值为8,*(C[2][0]+1)的值为8C[2][0][1]的值为8
*(*(C+2)+1)+0地址的值为7797392,*(C[2]+1)+0的值为7797392,C[2][1]+0的值为7797392,C[2][1][0]的地址为7797392
*(*(*(C+2)+1)+0)的值为11,*(*(C[2]+1)+0)的值为11,*(C[2][1]+0)的值为11C[2][1][0]的值为11
*(*(C+2)+1)+1地址的值为7797396,*(C[2]+1)+1的值为7797392,C[2][1]+1的值为7797396,C[2][1][1]的地址为7797396
*(*(*(C+2)+1)+1)的值为13,*(*(C[2]+1)+1)的值为13,*(C[2][1]+1)的值为13C[2][1][1]的值为13

转换公式:C[i][j][k] == *(C[i][j]+k) == *(*(C[i]+j)+k) == *(*(*(C+i)+j)+k)

多维数组作为参数

二维数组做参数:

  • void func(int (*Arr)[3])

  • void func(int Arr[][3])

  • void func(int **A)

三维数组做参数:

  • void func(int (*Arr)[2][2])

  • void func(int Arr[][2][2])

  • void func(int ***A)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
void func1(int Arr[][3])
{
printf("func1函数 - Arr的大小为%d, Arr[0]的大小为%d, Arr[0][0]的大小为%d\n", sizeof(Arr), sizeof(Arr[0]), sizeof(Arr[0][0]));
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
printf("Arr[%d][%d]的地址为%d,Arr[%d][%d]的值为%d\n", i, j, &Arr[i][j], i, j,Arr[i][j]);
}
}

}
void func2(int Arr[][2][2])
{
printf("func2函数 - Arr的大小为%d, Arr[0]的大小为%d, Arr[0][0]的大小为%d, Arr[0][0][0]的大小为%d\n", sizeof(Arr), sizeof(Arr[0]), sizeof(Arr[0][0]), sizeof(Arr[0][0][0]));
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 2; k++)
{
printf("Arr[%d][%d][%d]的地址为%d,Arr[%d][%d][%d]的值为%d\n", i, j, k, &Arr[i][j][k], i, j, k, Arr[i][j][k]);
}
}
}
}

int main() {
int A[2][2];
int B[2][3] = { {2, 3, 6}, {4, 5, 8} };
int C[3][2][2] = { { {2,5},{7,9} },{ {3,4},{6,1} },{ {0,8},{11,13} } };
int D[3][2][3];

printf("Main函数 - B的大小为%d, B[0]的大小为%d, B[0][0]的大小为%d\n", sizeof(B), sizeof(B[0]), sizeof(B[0][0]));
printf("Main函数 - B的地址为%d\n", B);
printf("Main函数 - C的大小为%d, C[0]的大小为%d, C[0][0]的大小为%d, C[0][0][0]的大小为%d\n", sizeof(C), sizeof(C[0]), sizeof(C[0][0]), sizeof(C[0][0][0]));
printf("Main函数 - C的地址为%d\n", C);

//func1(A); // 错误
func1(B); // 正确

func2(C); // 正确
//func2(D); // 错误

return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
void func1(int (*Arr)[3])
{
printf("func1函数 - Arr的大小为%d, Arr[0]的大小为%d, Arr[0][0]的大小为%d\n", sizeof(Arr), sizeof(Arr[0]), sizeof(Arr[0][0]));
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
printf("Arr[%d][%d]的地址为%d,Arr[%d][%d]的值为%d\n", i, j, &Arr[i][j], i, j,Arr[i][j]);
}
}

}
void func2(int (*Arr)[2][2])
{
printf("func2函数 - Arr的大小为%d, Arr[0]的大小为%d, Arr[0][0]的大小为%d, Arr[0][0][0]的大小为%d\n", sizeof(Arr), sizeof(Arr[0]), sizeof(Arr[0][0]), sizeof(Arr[0][0][0]));
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 2; k++)
{
printf("Arr[%d][%d][%d]的地址为%d,Arr[%d][%d][%d]的值为%d\n", i, j, k, &Arr[i][j][k], i, j, k, Arr[i][j][k]);
}
}
}
}

int main() {
int A[2][2];
int B[2][3] = { {2, 3, 6}, {4, 5, 8} };
int C[3][2][2] = { { {2,5},{7,9} },{ {3,4},{6,1} },{ {0,8},{11,13} } };
int D[3][2][3];

printf("Main函数 - B的大小为%d, B[0]的大小为%d, B[0][0]的大小为%d\n", sizeof(B), sizeof(B[0]), sizeof(B[0][0]));
printf("Main函数 - B的地址为%d\n", B);
printf("Main函数 - C的大小为%d, C[0]的大小为%d, C[0][0]的大小为%d, C[0][0][0]的大小为%d\n", sizeof(C), sizeof(C[0]), sizeof(C[0][0]), sizeof(C[0][0][0]));
printf("Main函数 - C的地址为%d\n", C);

//func1(A); // 错误
func1(B); // 正确

func2(C); // 正确
//func2(D); // 错误

return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Main函数 - B的大小为24, B[0]的大小为12, B[0][0]的大小为4
Main函数 - B的地址为15727220
Main函数 - C的大小为48, C[0]的大小为16, C[0][0]的大小为8, C[0][0][0]的大小为4
Main函数 - C的地址为15727164
func1函数 - Arr的大小为4, Arr[0]的大小为12, Arr[0][0]的大小为4
Arr[0][0]的地址为15727220,Arr[0][0]的值为2
Arr[0][1]的地址为15727224,Arr[0][1]的值为3
Arr[0][2]的地址为15727228,Arr[0][2]的值为6
Arr[1][0]的地址为15727232,Arr[1][0]的值为4
Arr[1][1]的地址为15727236,Arr[1][1]的值为5
Arr[1][2]的地址为15727240,Arr[1][2]的值为8
func2函数 - Arr的大小为4, Arr[0]的大小为16, Arr[0][0]的大小为8, Arr[0][0][0]的大小为4
Arr[0][0][0]的地址为15727164,Arr[0][0][0]的值为2
Arr[0][0][1]的地址为15727168,Arr[0][0][1]的值为5
Arr[0][1][0]的地址为15727172,Arr[0][1][0]的值为7
Arr[0][1][1]的地址为15727176,Arr[0][1][1]的值为9
Arr[1][0][0]的地址为15727180,Arr[1][0][0]的值为3
Arr[1][0][1]的地址为15727184,Arr[1][0][1]的值为4
Arr[1][1][0]的地址为15727188,Arr[1][1][0]的值为6
Arr[1][1][1]的地址为15727192,Arr[1][1][1]的值为1
Arr[2][0][0]的地址为15727196,Arr[2][0][0]的值为0
Arr[2][0][1]的地址为15727200,Arr[2][0][1]的值为8
Arr[2][1][0]的地址为15727204,Arr[2][1][0]的值为11
Arr[2][1][1]的地址为15727208,Arr[2][1][1]的值为13

动态内存

malloc、calloc、realloc

malloc

  • 函数签名:void* malloc(size_t size)。函数接收一个参数size,返回的void*指针指向了分配给我们的内存块中的第一个字节的地址。

  • void*类型的指针只能指明地址值,但是无法用于解引用,所以通常我们需要对返回的指针做强制类型转换,转换成我们需要的指针类型。

  • 通常我们不显式地给出参数size的值,而是通过sizeof,再乘上我们需要的元素个数,计算出我们需要的内存空间的大小。

1
2
3
4
5
6
7
8
9
10
int* a = (int*)malloc(3 * sizeof(int));
*a = 10;
*(a + 1) = 3;
a[2] = 2;

for (int i = 0; i < 3; i++)
{
printf("a[%d] = %d\n", i,a[i]);
}

1
2
3
4
a[0] = 10
a[1] = 3
a[2] = 2

calloc

  • 函数签名:void* calloc(size_t num, size_t size)。函数接收两个参数numsize,分别表示特定类型的元素的数量和类型的大小。同样返回一个void*类型的指针。

  • callocmalloc的另一个区别是:malloc分配完内存后不会对其进行初始化,calloc分配完内存后会将值初始化位0。

1
2
3
4
5
6
7
8
9
10
11
int* a = (int*)malloc(3 * sizeof(int));
for (int i = 0; i < 3; i++)
{
printf("a[%d] = %d\n", i,a[i]);
}

int* b = (int*)calloc(3 , sizeof(int));
for (int i = 0; i < 3; i++)
{
printf("b[%d] = %d\n", i, b[i]);
}
1
2
3
4
5
6
7
a[0] = -842150451
a[1] = -842150451
a[2] = -842150451
b[0] = 0
b[1] = 0
b[2] = 0

realloc

  • 函数签名:void* realloc(void* ptr, size_t size)。函数接收两个参数,第一个是指向已经分配的内存的起始地址的指针,第二个是要新分配的内存大小。返回void*指针。可能扩展原来的内存块,也可能另找一块大内存拷贝过去,如果是缩小的话,就会是原地缩小。

  • 如果缩小,或者拷贝到新的内存地址,总之只要是由原来分配的内存地址不会再被用到,realloc函数自己会将这些不被用到的地址释放掉。

放大与缩小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int n = 5;
int* a = (int*)malloc(n * sizeof(int));
for (int i = 0; i < n; i++)
{
a[i] = i;
printf("a[%d] = %d\n", i, a[i]);
}

int* b = (int*)realloc(a, 2 * n * sizeof(int));
printf("原先地址为%d,现在地址为%d\n", a, b);
for (int i = 0; i < 2 * n; i++)
{
printf("b[%d] = %d\n", i, b[i]);
}

int* c = (int*)realloc(a, (n / 2) * sizeof(int));
printf("原先地址为%d,现在地址为%d\n", a, c);
for (int i = 0; i < n; i++)
{
printf("c[%d] = %d\n", i, c[i]);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
a[0] = 0
a[1] = 1
a[2] = 2
a[3] = 3
a[4] = 4
原先地址为9596248,现在地址为9596248
b[0] = 0
b[1] = 1
b[2] = 2
b[3] = 3
b[4] = 4
b[5] = -842150451
b[6] = -842150451
b[7] = -842150451
b[8] = -842150451
b[9] = -842150451
原先地址为9596248,现在地址为9596248
c[0] = 0
c[1] = 1
c[2] = -33686019
c[3] = 3
c[4] = -405584600

realloc相当于free

1
int* b = (int*)realloc(a, 0);

realloc相当于malloc

1
int* a = (int*)realloc(NULL, sizeof(int));

malloc与free

一维数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int* p;

p = (int*)malloc(sizeof(int));
*p = 10;
printf("p所指向的地址为%d,p的值为%d\n", p, *p);
free(p);

p = (int*)malloc(3 * sizeof(int));
p[0] = 1;
p[1] = 2;
p[2] = 3;
for (int i = 0; i < 3; i++)
{
printf("p[%d]所指向的地址为%d,p[%d]的值为%d\n", i, p[i], i, &p[i]);
}
free(p);

1
2
3
4
5
p所指向的地址为11889848,p的值为10
p[0]所指向的地址为1,p[0]的值为11889848
p[1]所指向的地址为2,p[1]的值为11889852
p[2]所指向的地址为3,p[2]的值为11889856

二维数组

参考博客

二级指针

sizeof(int*),不能少*,一个指针的内存大小,每个元素是一个指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int row = 4, col = 5;
int** arr = (int**)malloc(sizeof(int*) * row);
for (int i = 0; i < row; i++)
{
arr[i] = (int*)malloc(sizeof(int) * col);
}

for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
arr[i][j] = col * i + j;
printf("arr[%d][%d]的地址为%d,arr[%d][%d]的值为%d\n", i, j, &arr[i][j], i, j, arr[i][j]);
printf("arr[%d]+%d的值为%d,*(arr[%d]+%d)的值为%d\n", i, j, arr[i] + j, i, j, *(arr[i] + j));
}
printf("地址开始不连续\n");
}

for (int i = 0; i < row; i++)
{
printf("arr+%d的地址为%d,arr[%d]的地址为%d\n", i, arr + i, i, &arr[i]);
printf("arr+%d所指向的值为%d,arr[%d]的值为%d\n", i, *(arr + i), i, arr[i]);
}

for (int i = 0; i < row; i++)
{
free(arr[i]);
}
free(arr);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
arr[0][0]的地址为17001880,arr[0][0]的值为0
arr[0]+0的值为17001880,*(arr[0]+0)的值为0
arr[0][1]的地址为17001884,arr[0][1]的值为1
arr[0]+1的值为17001884,*(arr[0]+1)的值为1
arr[0][2]的地址为17001888,arr[0][2]的值为2
arr[0]+2的值为17001888,*(arr[0]+2)的值为2
arr[0][3]的地址为17001892,arr[0][3]的值为3
arr[0]+3的值为17001892,*(arr[0]+3)的值为3
arr[0][4]的地址为17001896,arr[0][4]的值为4
arr[0]+4的值为17001896,*(arr[0]+4)的值为4
地址开始不连续
arr[1][0]的地址为17001488,arr[1][0]的值为5
arr[1]+0的值为17001488,*(arr[1]+0)的值为5
arr[1][1]的地址为17001492,arr[1][1]的值为6
arr[1]+1的值为17001492,*(arr[1]+1)的值为6
arr[1][2]的地址为17001496,arr[1][2]的值为7
arr[1]+2的值为17001496,*(arr[1]+2)的值为7
arr[1][3]的地址为17001500,arr[1][3]的值为8
arr[1]+3的值为17001500,*(arr[1]+3)的值为8
arr[1][4]的地址为17001504,arr[1][4]的值为9
arr[1]+4的值为17001504,*(arr[1]+4)的值为9
地址开始不连续
arr[2][0]的地址为17001552,arr[2][0]的值为10
arr[2]+0的值为17001552,*(arr[2]+0)的值为10
arr[2][1]的地址为17001556,arr[2][1]的值为11
arr[2]+1的值为17001556,*(arr[2]+1)的值为11
arr[2][2]的地址为17001560,arr[2][2]的值为12
arr[2]+2的值为17001560,*(arr[2]+2)的值为12
arr[2][3]的地址为17001564,arr[2][3]的值为13
arr[2]+3的值为17001564,*(arr[2]+3)的值为13
arr[2][4]的地址为17001568,arr[2][4]的值为14
arr[2]+4的值为17001568,*(arr[2]+4)的值为14
地址开始不连续
arr[3][0]的地址为17027432,arr[3][0]的值为15
arr[3]+0的值为17027432,*(arr[3]+0)的值为15
arr[3][1]的地址为17027436,arr[3][1]的值为16
arr[3]+1的值为17027436,*(arr[3]+1)的值为16
arr[3][2]的地址为17027440,arr[3][2]的值为17
arr[3]+2的值为17027440,*(arr[3]+2)的值为17
arr[3][3]的地址为17027444,arr[3][3]的值为18
arr[3]+3的值为17027444,*(arr[3]+3)的值为18
arr[3][4]的地址为17027448,arr[3][4]的值为19
arr[3]+4的值为17027448,*(arr[3]+4)的值为19
地址开始不连续
arr+0的地址为17001816,arr[0]的地址为17001816
arr+0所指向的值为17001880,arr[0]的值为17001880
arr+1的地址为17001820,arr[1]的地址为17001820
arr+1所指向的值为17001488,arr[1]的值为17001488
arr+2的地址为17001824,arr[2]的地址为17001824
arr+2所指向的值为17001552,arr[2]的值为17001552
arr+3的地址为17001828,arr[3]的地址为17001828
arr+3所指向的值为17027432,arr[3]的值为17027432

注:二级指针所指向的数组开辟的地址可能不是连续的

传递参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
void printarr(int** arr)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
printf("print -- arr[%d][%d]的地址为%d,arr[%d][%d]的值为%d\n", i, j, &arr[i][j], i, j, arr[i][j]);
}
printf("地址开始不连续\n");
}
}

int main()
{
int row = 4, col = 5;
int** arr = (int**)malloc(sizeof(int*) * row);
for (int i = 0; i < row; i++)
{
arr[i] = (int*)malloc(sizeof(int) * col);
}


for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
arr[i][j] = col * i + j;
printf("main -- arr[%d][%d]的地址为%d,arr[%d][%d]的值为%d\n", i, j, &arr[i][j], i, j, arr[i][j]);
}
printf("地址开始不连续\n");
}

printarr(arr);

free(arr);

return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
main -- arr[0][0]的地址为12610744,arr[0][0]的值为0
main -- arr[0][1]的地址为12610748,arr[0][1]的值为1
main -- arr[0][2]的地址为12610752,arr[0][2]的值为2
main -- arr[0][3]的地址为12610756,arr[0][3]的值为3
main -- arr[0][4]的地址为12610760,arr[0][4]的值为4
地址开始不连续
main -- arr[1][0]的地址为12610808,arr[1][0]的值为5
main -- arr[1][1]的地址为12610812,arr[1][1]的值为6
main -- arr[1][2]的地址为12610816,arr[1][2]的值为7
main -- arr[1][3]的地址为12610820,arr[1][3]的值为8
main -- arr[1][4]的地址为12610824,arr[1][4]的值为9
地址开始不连续
main -- arr[2][0]的地址为12610416,arr[2][0]的值为10
main -- arr[2][1]的地址为12610420,arr[2][1]的值为11
main -- arr[2][2]的地址为12610424,arr[2][2]的值为12
main -- arr[2][3]的地址为12610428,arr[2][3]的值为13
main -- arr[2][4]的地址为12610432,arr[2][4]的值为14
地址开始不连续
main -- arr[3][0]的地址为12610480,arr[3][0]的值为15
main -- arr[3][1]的地址为12610484,arr[3][1]的值为16
main -- arr[3][2]的地址为12610488,arr[3][2]的值为17
main -- arr[3][3]的地址为12610492,arr[3][3]的值为18
main -- arr[3][4]的地址为12610496,arr[3][4]的值为19
地址开始不连续
print -- arr[0][0]的地址为12610744,arr[0][0]的值为0
print -- arr[0][1]的地址为12610748,arr[0][1]的值为1
print -- arr[0][2]的地址为12610752,arr[0][2]的值为2
print -- arr[0][3]的地址为12610756,arr[0][3]的值为3
print -- arr[0][4]的地址为12610760,arr[0][4]的值为4
地址开始不连续
print -- arr[1][0]的地址为12610808,arr[1][0]的值为5
print -- arr[1][1]的地址为12610812,arr[1][1]的值为6
print -- arr[1][2]的地址为12610816,arr[1][2]的值为7
print -- arr[1][3]的地址为12610820,arr[1][3]的值为8
print -- arr[1][4]的地址为12610824,arr[1][4]的值为9
地址开始不连续
print -- arr[2][0]的地址为12610416,arr[2][0]的值为10
print -- arr[2][1]的地址为12610420,arr[2][1]的值为11
print -- arr[2][2]的地址为12610424,arr[2][2]的值为12
print -- arr[2][3]的地址为12610428,arr[2][3]的值为13
print -- arr[2][4]的地址为12610432,arr[2][4]的值为14
地址开始不连续
print -- arr[3][0]的地址为12610480,arr[3][0]的值为15
print -- arr[3][1]的地址为12610484,arr[3][1]的值为16
print -- arr[3][2]的地址为12610488,arr[3][2]的值为17
print -- arr[3][3]的地址为12610492,arr[3][3]的值为18
print -- arr[3][4]的地址为12610496,arr[3][4]的值为19
地址开始不连续

数组指针

申请一个 4行 5列的二维数组,注意,列数不能用未知参数确定

1
2
3
4
5
6
7
8
9
10
11
12
int(*arr)[5] = (int(*)[5])malloc(sizeof(int) * 4 * 5);
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
arr[i][j] = 5 * i + j;
printf("第%d行第%d列数组地址为%d,值为%d\n", i, j, &arr[i][j], arr[i][j]);
}
}

free(arr);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
第0行第0列数组地址为22506680,值为0
第0行第1列数组地址为22506684,值为1
第0行第2列数组地址为22506688,值为2
第0行第3列数组地址为22506692,值为3
第0行第4列数组地址为22506696,值为4
第1行第0列数组地址为22506700,值为5
第1行第1列数组地址为22506704,值为6
第1行第2列数组地址为22506708,值为7
第1行第3列数组地址为22506712,值为8
第1行第4列数组地址为22506716,值为9
第2行第0列数组地址为22506720,值为10
第2行第1列数组地址为22506724,值为11
第2行第2列数组地址为22506728,值为12
第2行第3列数组地址为22506732,值为13
第2行第4列数组地址为22506736,值为14
第3行第0列数组地址为22506740,值为15
第3行第1列数组地址为22506744,值为16
第3行第2列数组地址为22506748,值为17
第3行第3列数组地址为22506752,值为18
第3行第4列数组地址为22506756,值为19

参数传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void printarr(int arr[][5])
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
printf("print -- arr[%d][%d]的地址为%d,arr[%d][%d]的值为%d\n", i, j, &arr[i][j], i, j, arr[i][j]);
}
}
}

int main()
{
int(*arr)[5] = (int(*)[5])malloc(sizeof(int) * 4 * 5);
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
arr[i][j] = 5 * i + j;
printf("main -- 第%d行第%d列数组地址为%d,值为%d\n", i, j, &arr[i][j], arr[i][j]);
}
}

printarr(arr);

free(arr);

return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
main -- 第0行第0列数组地址为21130424,值为0
main -- 第0行第1列数组地址为21130428,值为1
main -- 第0行第2列数组地址为21130432,值为2
main -- 第0行第3列数组地址为21130436,值为3
main -- 第0行第4列数组地址为21130440,值为4
main -- 第1行第0列数组地址为21130444,值为5
main -- 第1行第1列数组地址为21130448,值为6
main -- 第1行第2列数组地址为21130452,值为7
main -- 第1行第3列数组地址为21130456,值为8
main -- 第1行第4列数组地址为21130460,值为9
main -- 第2行第0列数组地址为21130464,值为10
main -- 第2行第1列数组地址为21130468,值为11
main -- 第2行第2列数组地址为21130472,值为12
main -- 第2行第3列数组地址为21130476,值为13
main -- 第2行第4列数组地址为21130480,值为14
main -- 第3行第0列数组地址为21130484,值为15
main -- 第3行第1列数组地址为21130488,值为16
main -- 第3行第2列数组地址为21130492,值为17
main -- 第3行第3列数组地址为21130496,值为18
main -- 第3行第4列数组地址为21130500,值为19
print -- arr[0][0]的地址为21130424,arr[0][0]的值为0
print -- arr[0][1]的地址为21130428,arr[0][1]的值为1
print -- arr[0][2]的地址为21130432,arr[0][2]的值为2
print -- arr[0][3]的地址为21130436,arr[0][3]的值为3
print -- arr[0][4]的地址为21130440,arr[0][4]的值为4
print -- arr[1][0]的地址为21130444,arr[1][0]的值为5
print -- arr[1][1]的地址为21130448,arr[1][1]的值为6
print -- arr[1][2]的地址为21130452,arr[1][2]的值为7
print -- arr[1][3]的地址为21130456,arr[1][3]的值为8
print -- arr[1][4]的地址为21130460,arr[1][4]的值为9
print -- arr[2][0]的地址为21130464,arr[2][0]的值为10
print -- arr[2][1]的地址为21130468,arr[2][1]的值为11
print -- arr[2][2]的地址为21130472,arr[2][2]的值为12
print -- arr[2][3]的地址为21130476,arr[2][3]的值为13
print -- arr[2][4]的地址为21130480,arr[2][4]的值为14
print -- arr[3][0]的地址为21130484,arr[3][0]的值为15
print -- arr[3][1]的地址为21130488,arr[3][1]的值为16
print -- arr[3][2]的地址为21130492,arr[3][2]的值为17
print -- arr[3][3]的地址为21130496,arr[3][3]的值为18
print -- arr[3][4]的地址为21130500,arr[3][4]的值为19

一维数组模拟二维数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int row = 4, col = 5;

int* arr = (int*)malloc(sizeof(int) * row * col);

for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
arr[i * col + j] = col * i + j;
printf("arr[%d][%d]的地址为%d,arr[%d][%d]的值为%d\n", i, j, &arr[i * col + j], i, j, arr[i * col + j]);
}
}

free(arr);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
arr[0][0]的地址为15895056,arr[0][0]的值为0
arr[0][1]的地址为15895060,arr[0][1]的值为1
arr[0][2]的地址为15895064,arr[0][2]的值为2
arr[0][3]的地址为15895068,arr[0][3]的值为3
arr[0][4]的地址为15895072,arr[0][4]的值为4
arr[1][0]的地址为15895076,arr[1][0]的值为5
arr[1][1]的地址为15895080,arr[1][1]的值为6
arr[1][2]的地址为15895084,arr[1][2]的值为7
arr[1][3]的地址为15895088,arr[1][3]的值为8
arr[1][4]的地址为15895092,arr[1][4]的值为9
arr[2][0]的地址为15895096,arr[2][0]的值为10
arr[2][1]的地址为15895100,arr[2][1]的值为11
arr[2][2]的地址为15895104,arr[2][2]的值为12
arr[2][3]的地址为15895108,arr[2][3]的值为13
arr[2][4]的地址为15895112,arr[2][4]的值为14
arr[3][0]的地址为15895116,arr[3][0]的值为15
arr[3][1]的地址为15895120,arr[3][1]的值为16
arr[3][2]的地址为15895124,arr[3][2]的值为17
arr[3][3]的地址为15895128,arr[3][3]的值为18
arr[3][4]的地址为15895132,arr[3][4]的值为19

参数传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void printarr(int* arr)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
printf("print -- arr[%d][%d]的地址为%d,arr[%d][%d]的值为%d\n", i, j, &arr[i * 5 + j], i, j, arr[i * 5 + j]);
}
}
}

int main()
{
int row = 4, col = 5;

int* arr = (int*)malloc(sizeof(int) * row * col);

for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
arr[i * col + j] = col * i + j;
printf("main -- arr[%d][%d]的地址为%d,arr[%d][%d]的值为%d\n", i, j, &arr[i * col + j], i, j, arr[i * col + j]);
}
}

printarr(arr);

free(arr);

return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
main -- arr[0][0]的地址为19033272,arr[0][0]的值为0
main -- arr[0][1]的地址为19033276,arr[0][1]的值为1
main -- arr[0][2]的地址为19033280,arr[0][2]的值为2
main -- arr[0][3]的地址为19033284,arr[0][3]的值为3
main -- arr[0][4]的地址为19033288,arr[0][4]的值为4
main -- arr[1][0]的地址为19033292,arr[1][0]的值为5
main -- arr[1][1]的地址为19033296,arr[1][1]的值为6
main -- arr[1][2]的地址为19033300,arr[1][2]的值为7
main -- arr[1][3]的地址为19033304,arr[1][3]的值为8
main -- arr[1][4]的地址为19033308,arr[1][4]的值为9
main -- arr[2][0]的地址为19033312,arr[2][0]的值为10
main -- arr[2][1]的地址为19033316,arr[2][1]的值为11
main -- arr[2][2]的地址为19033320,arr[2][2]的值为12
main -- arr[2][3]的地址为19033324,arr[2][3]的值为13
main -- arr[2][4]的地址为19033328,arr[2][4]的值为14
main -- arr[3][0]的地址为19033332,arr[3][0]的值为15
main -- arr[3][1]的地址为19033336,arr[3][1]的值为16
main -- arr[3][2]的地址为19033340,arr[3][2]的值为17
main -- arr[3][3]的地址为19033344,arr[3][3]的值为18
main -- arr[3][4]的地址为19033348,arr[3][4]的值为19
print -- arr[0][0]的地址为19033272,arr[0][0]的值为0
print -- arr[0][1]的地址为19033276,arr[0][1]的值为1
print -- arr[0][2]的地址为19033280,arr[0][2]的值为2
print -- arr[0][3]的地址为19033284,arr[0][3]的值为3
print -- arr[0][4]的地址为19033288,arr[0][4]的值为4
print -- arr[1][0]的地址为19033292,arr[1][0]的值为5
print -- arr[1][1]的地址为19033296,arr[1][1]的值为6
print -- arr[1][2]的地址为19033300,arr[1][2]的值为7
print -- arr[1][3]的地址为19033304,arr[1][3]的值为8
print -- arr[1][4]的地址为19033308,arr[1][4]的值为9
print -- arr[2][0]的地址为19033312,arr[2][0]的值为10
print -- arr[2][1]的地址为19033316,arr[2][1]的值为11
print -- arr[2][2]的地址为19033320,arr[2][2]的值为12
print -- arr[2][3]的地址为19033324,arr[2][3]的值为13
print -- arr[2][4]的地址为19033328,arr[2][4]的值为14
print -- arr[3][0]的地址为19033332,arr[3][0]的值为15
print -- arr[3][1]的地址为19033336,arr[3][1]的值为16
print -- arr[3][2]的地址为19033340,arr[3][2]的值为17
print -- arr[3][3]的地址为19033344,arr[3][3]的值为18
print -- arr[3][4]的地址为19033348,arr[3][4]的值为19

结构体定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
typedef struct {
int a[5];
}item;

int main()
{
item* arr = (item*)malloc(sizeof(item) * 4);
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
(arr + i)->a[j] = 5 * i + j;
printf("arr[%d][%d]的地址为%d,arr[%d][%d]的值为%d\n", i, j, &((arr + i)->a[j]), i, j, (arr + i)->a[j]);
}
}

free(arr);

return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
arr[0][0]的地址为22834360,arr[0][0]的值为0
arr[0][1]的地址为22834364,arr[0][1]的值为1
arr[0][2]的地址为22834368,arr[0][2]的值为2
arr[0][3]的地址为22834372,arr[0][3]的值为3
arr[0][4]的地址为22834376,arr[0][4]的值为4
arr[1][0]的地址为22834380,arr[1][0]的值为5
arr[1][1]的地址为22834384,arr[1][1]的值为6
arr[1][2]的地址为22834388,arr[1][2]的值为7
arr[1][3]的地址为22834392,arr[1][3]的值为8
arr[1][4]的地址为22834396,arr[1][4]的值为9
arr[2][0]的地址为22834400,arr[2][0]的值为10
arr[2][1]的地址为22834404,arr[2][1]的值为11
arr[2][2]的地址为22834408,arr[2][2]的值为12
arr[2][3]的地址为22834412,arr[2][3]的值为13
arr[2][4]的地址为22834416,arr[2][4]的值为14
arr[3][0]的地址为22834420,arr[3][0]的值为15
arr[3][1]的地址为22834424,arr[3][1]的值为16
arr[3][2]的地址为22834428,arr[3][2]的值为17
arr[3][3]的地址为22834432,arr[3][3]的值为18
arr[3][4]的地址为22834436,arr[3][4]的值为19

参数传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
typedef struct {
int a[5];
}item;

void printarr(item* arr)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
printf("print -- arr[%d][%d]的地址为%d,arr[%d][%d]的值为%d\n", i, j, &((arr + i)->a[j]), i, j, (arr + i)->a[j]);
}
}
}

int main()
{
item* arr = (item*)malloc(sizeof(item) * 4);
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
(arr + i)->a[j] = 5 * i + j;
printf("main -- arr[%d][%d]的地址为%d,arr[%d][%d]的值为%d\n", i, j, &((arr + i)->a[j]), i, j, (arr + i)->a[j]);
}
}

printarr(arr);

return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
main -- arr[0][0]的地址为13528248,arr[0][0]的值为0
main -- arr[0][1]的地址为13528252,arr[0][1]的值为1
main -- arr[0][2]的地址为13528256,arr[0][2]的值为2
main -- arr[0][3]的地址为13528260,arr[0][3]的值为3
main -- arr[0][4]的地址为13528264,arr[0][4]的值为4
main -- arr[1][0]的地址为13528268,arr[1][0]的值为5
main -- arr[1][1]的地址为13528272,arr[1][1]的值为6
main -- arr[1][2]的地址为13528276,arr[1][2]的值为7
main -- arr[1][3]的地址为13528280,arr[1][3]的值为8
main -- arr[1][4]的地址为13528284,arr[1][4]的值为9
main -- arr[2][0]的地址为13528288,arr[2][0]的值为10
main -- arr[2][1]的地址为13528292,arr[2][1]的值为11
main -- arr[2][2]的地址为13528296,arr[2][2]的值为12
main -- arr[2][3]的地址为13528300,arr[2][3]的值为13
main -- arr[2][4]的地址为13528304,arr[2][4]的值为14
main -- arr[3][0]的地址为13528308,arr[3][0]的值为15
main -- arr[3][1]的地址为13528312,arr[3][1]的值为16
main -- arr[3][2]的地址为13528316,arr[3][2]的值为17
main -- arr[3][3]的地址为13528320,arr[3][3]的值为18
main -- arr[3][4]的地址为13528324,arr[3][4]的值为19
print -- arr[0][0]的地址为13528248,arr[0][0]的值为0
print -- arr[0][1]的地址为13528252,arr[0][1]的值为1
print -- arr[0][2]的地址为13528256,arr[0][2]的值为2
print -- arr[0][3]的地址为13528260,arr[0][3]的值为3
print -- arr[0][4]的地址为13528264,arr[0][4]的值为4
print -- arr[1][0]的地址为13528268,arr[1][0]的值为5
print -- arr[1][1]的地址为13528272,arr[1][1]的值为6
print -- arr[1][2]的地址为13528276,arr[1][2]的值为7
print -- arr[1][3]的地址为13528280,arr[1][3]的值为8
print -- arr[1][4]的地址为13528284,arr[1][4]的值为9
print -- arr[2][0]的地址为13528288,arr[2][0]的值为10
print -- arr[2][1]的地址为13528292,arr[2][1]的值为11
print -- arr[2][2]的地址为13528296,arr[2][2]的值为12
print -- arr[2][3]的地址为13528300,arr[2][3]的值为13
print -- arr[2][4]的地址为13528304,arr[2][4]的值为14
print -- arr[3][0]的地址为13528308,arr[3][0]的值为15
print -- arr[3][1]的地址为13528312,arr[3][1]的值为16
print -- arr[3][2]的地址为13528316,arr[3][2]的值为17
print -- arr[3][3]的地址为13528320,arr[3][3]的值为18
print -- arr[3][4]的地址为13528324,arr[3][4]的值为19

new与delete

一维数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int* p;

p = new int;
*p = 10;
printf("p所指向的地址为%d,p的值为%d\n", p, *p);
delete p;

p = new int[3];
p[0] = 1;
p[1] = 2;
p[2] = 3;
for (int i = 0; i < 3; i++)
{
printf("p[%d]所指向的地址为%d,p[%d]的值为%d\n", i, p[i], i, &p[i]);
}
delete[]p;

1
2
3
4
5
p所指向的地址为13987000,p的值为10
p[0]所指向的地址为1,p[0]的值为13987000
p[1]所指向的地址为2,p[1]的值为13987004
p[2]所指向的地址为3,p[2]的值为13987008

二维数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int** arr;
int row = 4, col = 5;

arr = new int* [row];
for (int i = 0; i < row; i++)
{
arr[i] = new int[col];
}

for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
arr[i][j] = 5 * i + j;
printf("arr[%d][%d]的地址为%d,arr[%d][%d]的值为%d\n", i, j, &arr[i][j], i, j, arr[i][j]);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
arr[0][0]的地址为16674200,arr[0][0]的值为0
arr[0][1]的地址为16674204,arr[0][1]的值为1
arr[0][2]的地址为16674208,arr[0][2]的值为2
arr[0][3]的地址为16674212,arr[0][3]的值为3
arr[0][4]的地址为16674216,arr[0][4]的值为4
arr[1][0]的地址为16673808,arr[1][0]的值为5
arr[1][1]的地址为16673812,arr[1][1]的值为6
arr[1][2]的地址为16673816,arr[1][2]的值为7
arr[1][3]的地址为16673820,arr[1][3]的值为8
arr[1][4]的地址为16673824,arr[1][4]的值为9
arr[2][0]的地址为16673872,arr[2][0]的值为10
arr[2][1]的地址为16673876,arr[2][1]的值为11
arr[2][2]的地址为16673880,arr[2][2]的值为12
arr[2][3]的地址为16673884,arr[2][3]的值为13
arr[2][4]的地址为16673888,arr[2][4]的值为14
arr[3][0]的地址为16699752,arr[3][0]的值为15
arr[3][1]的地址为16699756,arr[3][1]的值为16
arr[3][2]的地址为16699760,arr[3][2]的值为17
arr[3][3]的地址为16699764,arr[3][3]的值为18
arr[3][4]的地址为16699768,arr[3][4]的值为19

内存泄漏

  • allocate_stack函数调用时,每次将数组创建在栈区,然后再函数返回时,程序自动将其栈帧释放,数组也被释放掉,不会占用内存。

  • 对于调用allocate_heap的程序:每次调用allocate_heap堆区开辟一个数组Arr,在栈上只创建了一个指针p来指向这个堆区数组,但是堆区数组没有释放,这样在allocate_heap函数返回之后,函数栈帧上的p也被程序释放掉,就再也没有办法去释放堆区的数组Arr

随着allocate_heap函数调用次数越来越多,堆区的数组都处于已分配但无法引用也无法使用的状态。而堆区大小又是不固定的,可以一直向操作系统申请,终会超过内存上限,造成了内存泄漏。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
void allocate_stack() {
int Arr[10000];
}

void allocate_heap() {
int* Arr = (int*)malloc(10000 * sizeof(int));
}

int main()
{
int choice;
while (1) {
printf("'0' 退出, '1' allocate_stack, '1' allocate_heap\n");
scanf("%d", &choice);
if (choice == 1)
{
for (int i = 0; i < 100; i++)
{
allocate_stack();
}
}
else if(choice == 2)
{
for (int i = 0; i < 100; i++)
{
allocate_heap();
}
}
else
{
break;
}
}

return 0;
}

函数返回指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int* Add(int* a, int* b)
{
int c = (*a) + (*b);
printf("Add函数中,c的地址为%d,c = %d\n", &c, c);
return &c;
}

void printHelloWorld()
{
printf("Hello World\n");
}

int main()
{
int x = 2, y = 4;
int* ptr = Add(&x, &y);
printf("main函数中,ptr的地址为%d\n", ptr);
printHelloWorld();
printf("x + y = %d\n", *ptr);

return 0;
}

1
2
3
4
5
Add函数中,c的地址为7797968,c = 6
main函数中,ptr的地址为7797968
Hello World
x + y = -858993460

注:在Add函数返回之后,它在栈区上的栈帧也被程序自动释放了,这个时候,原来存放整型变量c的内存地址中的值就已经是未知的了,访问未知的内存是极其危险的。

通常,计算机可以安全地返回堆区或者全局区的内存指针,因为它们不会被程序自动地释放。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int* Add(int* a, int* b)
{
int* c = (int*)malloc(sizeof(int));
(*c) = (*a) + (*b);
printf("Add函数中,c的地址为%d,c = %d\n", &c, *c);
return c;
}

void printHelloWorld()
{
printf("Hello World\n");
}

int main()
{
int x = 2, y = 4;
int* ptr = Add(&x, &y);
printf("main函数中,ptr的地址为%d\n", ptr);
printHelloWorld();
printf("x + y = %d\n", *ptr);
free(ptr);

return 0;
}

1
2
3
4
5
Add函数中,c的地址为7337652,c = 6
main函数中,ptr的地址为10710200
Hello World
x + y = 6

函数指针

指针函数的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
int Add(int a, int b)
{
return a + b;
}

int mul(int a, int b)
{
return b * a;
}

void PrintHello(char* uni)
{
printf("Hello %s ,I am coming!\n", uni);
}

int main()
{
int c;
int (*p)(int, int);
p = &Add;
c = (*p)(2, 3);
printf("和为%d\n", c);

p = mul;
c = p(2, 3);
printf("积为%d\n", c);

void (*ptr)(char*);
ptr = PrintHello;
ptr("bnu");

return 0;
}

1
2
3
4
和为5
积为6
Hello bnu ,I am coming!

  • 声明函数指针的语法:int (*p)(int, int),这条语句声明了一个接收两个整型变量作为参数,并且返回一个整型变量的函数指针。

  • 注意指针要加括号。否则int *p(int, int),是声明一个函数名为p,接收两个整型,并返回一个整型指针的函数。

  • 注意函数指针可以指向一类函数,指针p指向的类型是输入两整型,输出一整型的这一类函数,即所有满足这个签名的函数,都可以赋值给p这个函数指针。如以下这些函数指针的声明都是不能指向Add函数的:

    • void (*p)(int, int);
    • int (*p)(int);
    • int (*p)(int, char);
  • 函数指针赋值:p = &Add,将函数名为Add的函数指针赋值给p。同样注意只要满足p声明时的函数签名的函数名都可以赋值给p

  • 函数指针的使用:int c = (*p)(2, 3),先对p解引用得到函数Add,然后正常传参和返回即可。

  • 在为函数指针赋值时,可以不用取地址符号&,仅用函数名同样会返回正确的函数地址。与之匹配的,在调用函数的时候也不需要再解引用。

回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void A() {
printf("Hello World!\n");
}

void B(void (*ptr)()) {
ptr();
}

int main() {
void (*p)() = A;
B(p);

B(A);

return 0;
}

1
2
3
Hello World!
Hello World!

将函数A()的函数指针传给B()B()在函数体内直接通过传入的函数指针调用函数A(),这个过程成为回调。这里函数指针被传入另一个函数,再被用函数指针进行回调的函数A()成为回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
void BubbleSort(int A[], int size, int (*compare)(int, int))
{
int i, j, temp;
for (i = 0; i < size; i++) {
for (j = 0; j < size - 1; j++) {
if (compare(A[j], A[j + 1]) > 0) {
temp = A[j];
A[j] = A[j + 1];
A[j + 1] = temp;
}
}
}
}

int greater(int a, int b)
{
if (a > b) return 1;
else return -1;
}

int abs_greater(int a, int b)
{
if (abs(a) > abs(b)) return 1;
else return -1;
}

int main()
{
int c;
int A[] = { 2, -4, -1, 3, 9, -5, 7 };
int size = sizeof(A) / sizeof(A[0]);
printf("升序 - 1 ,绝对值升序 - 0 :");
scanf_s("%d", &c);
if (c == 1)
{
BubbleSort(A, size, greater);
}
else
{
BubbleSort(A, size, abs_greater);
}
int i = 0;
for (i = 0; i < size; i++) {
printf("A[%d] = %d ", i, A[i]);
}
printf("\n");
}

1
2
3
4
5
6
升序 - 1 ,绝对值升序 - 0 :1
A[0] = -5 A[1] = -4 A[2] = -1 A[3] = 2 A[4] = 3 A[5] = 7 A[6] = 9

升序 - 1 ,绝对值升序 - 0 :0
A[0] = -1 A[1] = 2 A[2] = 3 A[3] = -4 A[4] = -5 A[5] = 7 A[6] = 9

结构体

结构体定义

结构体成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct Student
{
int id;
char* name;
int age;
float score;
//...
};

int main()
{
struct Student stu;

return 0;
}

空结构体

1
2
3
4
5
struct EmptyStruct
{
//TODO
};

匿名结构体

1
2
3
4
5
6
7
8
9
struct
{
int id;
char* name;
int age;
float score;
//...
}stu1, stu2;

typedef定义数据类型

1
typedef struct Student Student;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef struct Student
{
int id;
char* name;
int age;
float score;
//......
}Student;

int main()
{
Student stu;

return 0;
}

结构体嵌套定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
typedef struct Birthday
{
int year;
int month;
int day;
}Birthday;

typedef struct Student
{
int id;
char* name;
int age;
float score;
Birthday birthday;
//...
}Student;

int main()
{
Student stu;
stu.birthday.day = 1;//多层访问
return 0;
}

结构体变量

结构体变量声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedef struct Student
{
int id;
char* name;
int age;
float score;
//...
}Student, stu3;

int main()
{
Student stu1, stu2;
return 0;
}

结构体变量赋值

1
2
Student stu1 = { 666,"花瓶",18,100,{2022,8,25} };
Student stu2 = { 555,"鲁花瓶",20,99,{2000,1,1} };

访问结构体变量成员

1
2
3
4
5
6
7
8
9
10
11
12
printf("学号:%d\t",stu1.id);
printf("姓名:%s\t", stu1.name);
printf("年龄:%d\t", stu1.age);
printf("成绩:%.2f\t", stu1.score);
printf("生日:%d-%d-%d\n", stu1.birthday.year, stu1.birthday.month, stu1.birthday.day);

printf("学号:%d\t", stu2.id);
printf("姓名:%s\t", stu2.name);
printf("年龄:%d\t", stu2.age);
printf("成绩:%.2f\t", stu2.score);
printf("生日:%d-%d-%d\n", stu2.birthday.year, stu2.birthday.month, stu2.birthday.day);

1
2
3
学号:666        姓名:花瓶       年龄:18 成绩:100.00     生日:2022-8-25
学号:555 姓名:鲁花瓶 年龄:20 成绩:99.00 生日:2000-1-1

结构体作为函数参数

1
2
3
4
5
6
7
8
9
void printstudentInfo(Student stu)
{
printf("学号:%d\t", stu.id);
printf("姓名:%s\t", stu.name);
printf("年龄:%d\t", stu.age);
printf("成绩:%.2f\t", stu.score);
printf("生日:%d-%d-%d\n", stu.birthday.year, stu.birthday.month, stu.birthday.day);
}

1
2
printstudentInfo(stu1);
printstudentInfo(stu2);
1
2
3
学号:666        姓名:花瓶       年龄:18 成绩:100.00     生日:2022-8-25
学号:555 姓名:鲁花瓶 年龄:20 成绩:99.00 生日:2000-1-1

结构体指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
typedef struct Birthday
{
int year;
int month;
int day;
}Birthday;

typedef struct Student
{
int id;
char* name;
int age;
float score;
Birthday birthday;
//...
}Student;

void printstudentInfo(Student* stu)
{
printf("学号:%d\t", stu->id);
printf("姓名:%s\t", stu->name);
printf("年龄:%d\t", stu->age);
printf("成绩:%.2f\t", stu->score);
printf("生日:%d-%d-%d\n", stu->birthday.year, stu->birthday.month, stu->birthday.day);
}

int main()
{
Student stu1 = { 666,"花瓶",18,100,{2022,8,25} };
Student stu2 = { 555,"鲁花瓶",20,99,{2000,1,1} };

Student* pstu = &stu1;
printstudentInfo(pstu);
pstu = &stu2;
printstudentInfo(pstu);

return 0;
}

1
2
3
学号:666        姓名:花瓶       年龄:18 成绩:100.00     生日:2022-8-25
学号:555 姓名:鲁花瓶 年龄:20 成绩:99.00 生日:2000-1-1

注:结构体指针在访问成员时,不能使用点.,必须使用箭头->

结构体数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void printstudentInfo(Student* stu, int size)
{
for (int i = 0; i < size; i++)
{
printf("学号:%d\t", (stu + i)->id);
printf("姓名:%s\t", (stu + i)->name);
printf("年龄:%d\t", (stu + i)->age);
printf("成绩:%.2f\t", (stu + i)->score);
printf("生日:%d-%d-%d\n", (stu + i)->birthday.year, (stu + i)->birthday.month, (stu + i)->birthday.day);
}
}

int main()
{
Student stu[] = { { 666,"花瓶",18,100,{2022,8,25} } , { 555,"鲁花瓶",20,99,{2000,1,1} } };

printstudentInfo(stu, sizeof(stu) / sizeof(Student));

return 0;
}

等价写法:(stu + i)->id)等价于stu[i].id

1
2
3
4
5
6
7
8
9
10
11
12
void printstudentInfo(Student* stu, int size)
{
for (int i = 0; i < size; i++)
{
printf("学号:%d\t", stu[i].id);
printf("姓名:%s\t", stu[i].name);
printf("年龄:%d\t", stu[i].age);
printf("成绩:%.2f\t", stu[i].score);
printf("生日:%d-%d-%d\n", stu[i].birthday.year, stu[i].birthday.month, stu[i].birthday.day);
}
}

1
2
3
学号:666        姓名:花瓶       年龄:18 成绩:100.00     生日:2022-8-25
学号:555 姓名:鲁花瓶 年龄:20 成绩:99.00 生日:2000-1-1

结构体内存的计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
typedef struct Birthday
{
int year;
int month;
int day;
}Birthday;

typedef struct Student
{
int id;
char* name;
int age;
float score;
Birthday birthday;
//...
}Student;

int main()
{
printf("int所占字节数:%d\n", sizeof(int));
printf("double所占字节数:%d\n", sizeof(double));
printf("float所占字节数:%d\n", sizeof(float));

printf("生日结构体所占字节数:%d\n", sizeof(Birthday));
printf("学生结构体所占字节数:%d\n", sizeof(Student));

return 0;
}

1
2
3
4
5
int所占字节数:4
double所占字节数:8
float所占字节数:4
生日结构体所占字节数:12
学生结构体所占字节数:28