数组参数传递
我们先看个例子,main入口 ,同样的代码打印的信息不一样。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 print2(int* arr) {
int len = sizeof(arr) / sizeof(int);
printf("len =%d\n", len);//len = 1
int i = 0;
for (; i < len; i++) {
printf("%d\n", arr[i]);
}
}
void print(int arr[]) {
int len = sizeof(arr) / sizeof(int);
printf("len =%d\n", len);//len = 1
int i = 0;
for (; i < len; i++) {
printf("%d\n", arr[i]);
}
}
int main()
{
int arr[] = { 1,2,3,4,5 };
int len = sizeof(arr) / sizeof(int);
printf("len =%d\n", len);//len = 5
print(arr);
printf("===================\n");
print2(arr);
printf("===================\n");
getchar();
return 0;
}
从这demo我们可以看到,数组作为参数传递的时候为什么获取不到长度?
数组作为参数传递,会退化成为一个指针,传递的是首地址 (高效)
数据类型剖析
- 数据类型本质: 一块连续大小的内存空间
demo11
2int a; //告诉c和c++编译器开辟一块连续大小的4字节的内存空间
a =32;
demo21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23int main()
{
int arr[] = { 1,2,3,4,5 };//内存大小空间 4x5=20
printf("%d , %d,%d ,%d", arr,arr+1,&arr,&arr+1);// 17758788 ,17758792,17758788 ,17758808
getchar();
return 0;
}
```
2. 数据类型别名
```c
/* Primitive types that match up with Java equivalents. */
typedef uint8_t jboolean; /* unsigned 8 bits */
typedef int8_t jbyte; /* signed 8 bits */
typedef uint16_t jchar; /* unsigned 16 bits */
typedef int16_t jshort; /* signed 16 bits */
typedef int32_t jint; /* signed 32 bits */
typedef int64_t jlong; /* signed 64 bits */
typedef float jfloat; /* 32-bit IEEE 754 */
typedef double jdouble; /* 64-bit IEEE 754 */
/* "cardinal indices and sizes" */
typedef jint jsize;
- void* 代表任意的数据类型的指针
变量的本质
- 变量的本质:固定内存块大小(一块连续大小的内存空间)的别名,通过变量去操作一块内存上的数据
- 变量的三要素:内存大小,名称,作用域
内存四驱模型
程序运行流程
- 操作系统会将物理磁盘上的代码load到内存
- 加载到内存后会将c代码分为4个区
- 后系统找到main程序入口运行
四驱模型
- 栈区: 由编译器自动分配的,存放一些局部变量和函数,内存会自动进行回收。
- 堆区: 一般由开发者自己开辟的,内存需要手动释放 malloc–>free new–>delete等。
- 全局区(数据区): 静态的一些常量,字符串等。
- 程序代码区: 存放函数的二进制代码。
1 |
|
不管是基本数据类型还是结构体,c都是值传递,和java不同的是,java基本数据类型是值传递,对象是引用传递。所以在c当中一般都是指针传递
change(int number)
changep(int* p_number)
栈的开口方向1
2
3
4
5int a=5;//先入栈
int buffer[]={1,2,3};
int b=7;
fprint("%p , %p",&a,&b);
如果地址a>b(debug),说明开口向下。
a<b(release)开口向上。
buffer数据类型的方向和栈的开口方向没关系,都是向上。&buffer[0]>&buffer[1]
指针强化
指针也是一种数据类型,虽然占用四个字节,但是有数据类型。
野指针1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23struct Student{
int age;
};
void main() {
Student* student =(Student*)malloc(sizeof(Student));
//释放的时候记得判断为NULL
if (student != NULL) {
free(student);//这个时候student变为野指针
//我们不需要的话最好置为NULL
student = NULL;
}
//释放的时候记得判断为NULL,这个时候就不会去free,从而避免错误
if (student != NULL) {
free(student);
}
getchar();
}
NULL
NULL也是一个内存指针,指针指向00000000,只不过我们不能进行操作。1
2
printf("NULL=%p", NULL); //NULL=00000000
字符串和 buffer 强化
1 |
|
char * ,char[],malloc
区别:前两个都是在栈里开辟内存,字符串放在常量区,数组定义的是将常量区的数据copy过来到char[]
里面(这样的话栈里也有了数据),char*
是直接指针指向常量,malloc
的方式是在堆里面开辟内存,存储数据到堆里。从而可以知道,字符串可以在任何区域开辟内存。
如图,栈中从上往下依次是char[],char*,malloc()
开发模型强化
- 确定参数,传递指针
- 一定要考略健壮性
- 异常错误,抛出说明
- 不要直接轻易的去改变调用者传递给你的指针,如需必要可以先考略临时的变量操作。可以加上const修饰参数强制不可修改。
1 | struct AndroidBitmapInfo{ |
结构体强化
在
c
中=
是赋值操作。1
2
3
4
5
6
7
8
9
10
11
12
13typedef struct {
char name[50];
int age;
}Student;
void main() {
Student stu1 = {"张三",35};
Student stu2;
stu2 = stu1;
printf("%p , %p \n", &stu1, &stu2);//007CFD7C , 007CFD3C
printf("%s , %d \n", stu2.name, stu2.age);//张三 , 35
getchar();
}在结构体里面套指针
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
//结构体套指针,必须要对结构体指针进行初始化(赋值)
//指针可以指向任何地址,但是它的大小永远是4字节
typedef struct {
char* name;// 定义了一个name指针
int age;
}Student;
void main() {
Student stu;
// 1.
//stu.name = "李四"; // 将指针指向常量区的"李四"
//2.
//往stu.name里面copy数据 "李四" 不能直接copy
//strcpy(stu.name, "李四");
//3.
//首先把char* name 指向堆区开辟的内存 ,然后把常量区的数据"李四" copy到堆里面
stu.name =(char*) malloc(100);
strcpy(stu.name, "李四");
stu.age = 35;
printf("%s , %d \n", stu.name, stu.age);//李四 , 35
getchar();
}深
copy
和浅copy
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
typedef struct {
char *name;
int age;
}Student;
void copyToP(Student* from, Student *to) {
//浅copy
*to = *from;
//深copy
to->name = (char*)malloc(100);//开辟内存
strcpy(to->name, from->name);//copy值
};
void main() {
char * name =(char*) malloc(100);
Student stu = {name,25};
strcpy(stu->name, "张三");
stu.age = 35;
printf("%s , %d \n", stu.name, stu.age);//张三 , 35
Student stu2 = {"李四",15};
copyToP(&stu2,&stu);
printf("%s , %d \n", stu2.name, stu2.age);//张三 , 35
if (stu.name) {
free(stu.name);
stu.name = NULL;
}
if (stu2.name) {//如果是浅copy会释放出错,因为stu.name和stu2.name指向一个位置 stu.name已经free了
free(stu2.name);
stu2.name = NULL;
}
getchar();
}结构体的偏移量 :见c基础的结构体内存开辟以及内存计算