c指针
大一记载的笔记:
动态内存和静态内存的比较 静态内存是有系统自动分配,由系统自动释放 静态内存是在栈分配的 动态内存是由程序员手动分配, 手动释放 动态内存是在堆内存分配的 地址一般用十六进制表示(H) 指针就是地址, 地址就是指针 地址就是内存单元的编号,不是编码。 指针变量是存放地址的变量 指针和指针变量是两个不同的概念 但是要注意:通常我们叙述时会把指针变量简称为指针, 实际他们的含义并不一样 附注: 1:乘法 2:定义指针变量 int * p //定义了一个名字叫p的变量, int *表示p只能存放int变量的地址 3:指针运算符 该运算符放在已经定义好的指针变量的前面 如果p是一个已经定义好的指针变量 则*p表示 以p的内容为地址的变量 // 重要 如何通过被调函数修改主调函数的普通变量的值 1. 实参必须为该普通变量的地址 2. 形参必须为指针变量 3. 在被调函数中通过 *形参名 = 。。。。 的方式就可以修改主调函数相关变量的值 指针: 指针的重要性 表示一些复杂的数据结构 快速的传递数据 使函数返回一个以上的值 能直接访问硬件 能够方便的处理字符串 是理解面向对象语言中引用的基础 指针的定义 地址 内存单元的编号 从零开始的非负整数 范围:4g (0--4g-1) 指针 地址一般用十六进制表示(H) 指针就是地址, 地址就是指针 地址就是内存单元的编号 指针变量是存放地址的变量 指针和指针变量是两个不同的概念 但是要注意:通常我们叙述时会把指针变量简称为指针, 实际他们的含义并不一样 指针的本质就是一个操作受限的非负整数 指针的分类 1. 基本类型的指针 2. 指针和数组 指针和一维数组名 一维数组名是个指针常量 它存放的是一维数组的第一个元素的地址 下标和指针的关系 如果p是个指针变量,则 p[i]永远等价于*(p + i) //知识要点 确定一个一维数组需要几个参数【如果一个函数要处理一个一维数组,则需要接受该数组哪些信息】 需要两个参数: 数组的第一个元素的地址 数组的长度 指针的运算 指针变量的的运算 指针变量不能相加 不能相乘 也不能相除 如果两个指针变量指向的是同一块连续空间中的不同存储单元,则这两个指针变量才能相减 一个指针变量到底占几个字节【非重点】 预备知识: sizeof(数据类型) 功能:返回值就是该数据类型所占的字节数 例子:sizeof(double) = 8 sizeof(变量名) 功能:返回值是该变量所占的字节数 假设p指向char类型变量(1个字节) 假设q指向int类型变量(4个字节) 假设r指向double类型变量(8个字节) p q r 本身所占的字节数是否一样? 答案:是 总结: 一个指针变量,无论它指向的变量占几个字节该指针变量值占四个字节 一个变量的地址使用该变量的首字节的地址来表示 指针和和二维数组 3. 指针和函数 4. 指针和结构体 3. 多级指针 专题: 动态内存分配 传统数组的缺点: 1:数组的长度必须事先制定,且只能是长整数,不能是变量 例子: int a[5]; //ok int len = 5; int a[len]; //error 2: 传统形式定义的数组,该数组的内存程序员无法手动释放 在一个函数运行期间, 系统为该函数中数组所分配的空间会一直存在, 直到该函数运行完毕时,数组的空间才会被系统释放 3: 数组的长度一旦定义,其长度就不能再更改 数组的长度不能再函数运行过程中动态的扩充或缩小 4: A函数定义的数组,在A函数运行期间可以被其他函数使用,但A函数运行完毕之后,A函数中的数组将无法再被其他函数使用 传统方式定义的数组不能跨函数使用 为什么需要动态分配内存 动态数组很好的解决了传统数组的这4个缺陷 传统数组也叫静态数组 动态内存分配的举例_动态数组的构造 静态内存和动态内存的比较 跨函数使用内存的问题 1 # include <stdio.h> int main(void) { int *p; //p是变量的名字, int *表示p变量存放的是int类型变量的地址 int i = 3; p = &i; //ok //p = 55; //error; //p = i; //error 因为类型不一致, p只能存放int类型变量的地址 } 2 # include <stdio.h> int main(void) { int * p; //p是变量的名字, int *表示p变量存放的是int类型变量的地址 //int *p;不表示定义了一个名字叫做*p的变量 //int *p;应该这样理解:p是变量名, p变量的数据类型是int *p类型 // 所谓int *;类型实际就是存放int变量地址的类型 int i = 3; p = &i; /* 1. p保存了i的地址, 因此p指向了i 2.p不是i, i也不是p, 更准确的说:修改了p的值不影响i的值修改了i的值也不影响p的值 3.如果一个指针变量指向了某个普通变量,则 *p 就完全等同义 普通变量 例子: 如果p是个指针变量, 并且p存放了普通变量i的地址 则p指向了普通变量i *p 就完全等同于 i 或者说:在所有出现了*p的地方都可以替换成i 在所有出现i的地方都可以替换成*p *p就是以p的内容为地址的变量 */ } 3 # include <stdio.h> int main(void) { int i = 5; int *p; *p = i;//error p的地址不明确 //加上p = &i程序就不会出错, printf("%d\n", *p); } 4 # include <stdio.h> int main(void) { int i = 5; int * p; int * q; p = &i; //*q = p; //error 语法编译出错 //*q = *p; //error p = q; // q 是垃圾值, q赋给p, p也变成垃圾值 printf("%d\n", * q); /* q的空间是属于本程序的, 所以本程序可以读写q的内容, 但是如果q内部是垃圾值, 则本程序不能读写*q的内容 */ } 5 # include <stdio.h> int main(void) { int a = 3, b = 5; int t; t = a; a = b; b = t; printf("a = %d, b = %d\n", a, b); } 6 //互换不了a和b的值 # include <stdio.h> void huhuan(int a, int b) { int t; t = a; a = b; b = t; return; } int main(void) { int a =4, b = 6; huhuan(a, b); printf("a = %d, b = %d\n", a, b); } 7 //互换不了a和b的值 //函数void huhuan(int * p, int * q)中的功能是交换了p和q的值,而不是a和b的值 # include <stdio.h> void huhuan(int * p, int * q) { int * t; //如果要互换p和q的值,则必须是int *, 不能是int, 否则会出错 t = p; p = q; q = t; } int main(void) { int a = 45, b = 3; huhuan(&a, &b); //huhuan(*p, *q);是错误的,huhuan(a, b);也是错误的,因为是类型不一致 printf("a = %d, b = %d\n", a, b); } 8 //互换得了a和b的值 # include <stdio.h> void huhuan(int * p, int * q) { int t; //如果要互换*p和*q的值,则t必须定义成int,不能定义成int *,否则语法错误 t = *p; //p是int *, *p是int *p = *q; *q = t; } int main(void) { int a = 45, b = 3; huhuan(&a, &b); //huhuan(*p, *q);是错误的,huhuan(a, b);也是错误的 printf("a = %d, b = %d\n", a, b); } 9 # include <stdio.h> int main(void) { int i = 45; char ch = 'A'; int * p; //等价于int *p;也等价于int* p; p = &i; //*p是以p的内容为地址的变量 *p = 99; printf("i = %d, *p = %d\n", i, *p); //注意了, 两者输出的值都是99;与上一行有和关联呢?。。。 //p = &ch //p = ch;//error //p = 5;//error return 0; } 10 # include <stdio.h> int f(int j) { int i = 99; return i; } int main(void) { int i; i = 66; printf("i = %d\n", i); f(i); printf("i = %d\n", f(i)); } 11 //使函数返回一个以上的值 // ab的值变成了void f(int * p, int * q)里面的值 # include <stdio.h> void f(int * p, int * q) { *p = 35; *p = 77; } int main(void) { int a = 5, b = 66; f(&a, &b); printf("a = %d, b = %d\n", a, b); return 0; } 12 # include <stdio.h> int main(void) { int a[5]; int b[5]; //int a[3][4];// a[i][j] //a = b; //error //a是常量 printf("%#X", &a[0]); printf("%#x", a); } 13 # include <stdio.h> //f函数可以输出任何一个一维数组的内容 void f(int *pArr, int len) { int i; for(i = 0; i < len; i ++) { printf("%d", * (pArr + i));//p[i]永远等价于*(p + i) } } printf("\n"); } int main(void) { int a[5] = {1, 3, 4, 5, 6}; int b[7] = {5, 6, 7, 8, 8}; int c[15] = {57, 78, -4, 889, 90}; //a = a[4]; //error //因为a是长量 f(a, 5); //a是int * f(b, 7); f(c, 15); return 0; } 14 //要明白pAr[3] 和 a[3] 是同一个变量 # include <stdio.h> void f(int *pArr, int len) { pArr[3] = 88; //等价于*(pArr + 3), 也等价于*[a + i], 也等价于a[i] //重点:p[i]永远等价于*(p + i) } int main(void) { int a[6] = {1, 3, 4, 5, 6, 7}; printf("%d\n", a[3]); f(a, 6); printf("%d\n", a[3]); return 0; } 15 //修该了i的值 # include <stdio.h> void f(int * i) { *i = 34; } int main(void) { int i = 8; printf("i = %d\n", i); f(&i); printf("i = %d\n", i); } 16 //指针的运算 # include<stdio.h> int main(void) { int i = 5; int j = 10; int * p = &i; int * q = &j; int a[5]; p = &a[1]; q = &a[4]; printf("p和q所指向的单元相隔%d个单元\n", q - p); } 17 //指针的运算 # include<stdio.h> int main(void) { int i = 5; int j = 10; int * p = &i; int * q = &j; //p - q没有实际意义 } 18 # include <stdio.h> int main(void) { int i = 5; char ch = 'a'; double j = 56.5; int * p; char * q; double * z; p = &i; q = &ch; z = &j; printf("%d, %d, %d\n", sizeof(p), sizeof(q), sizeof(z)); } 19 # include <stdio.h> void g(int * pArr, int len) { pArr[2] = 88; } void f() //f()函数中止后, 函数里面的数组就不能被其他函数使用了, 因为它已经释放掉了 { int a[5] = {1, 2, 3, 4, 5};//20个字节的存储空间程序员无法手动编程释放它, //它只能在本函数运行完毕是由系统自动释放 g(a, 5); printf("%d\n", a[2]); } int main(void) { f(); return 0; } 20 //malloc 是memory(内存) allocate(分配)的缩写 # include <stdio.h> # include <malloc.h> int main(void) int i = 5; //分配了4个字节 静态分配 //11 int * p = (int *)malloc(4); //12 /* 1. 要使用malloc函数, 必须添加malloc.h这个头文件 2. malloc函数只有一个形参, 并且形参是整型 3. 4表示请系统为本程序分配4个字节 4. malloc函数只能返回第一个字节的地址 5. 12分配了8个字节, p变量占4个字节, p所指向的内存也占4个字节 6. p本身所占的内存是静态分配的, p所指向的内存是动态分配的 */ *p = 5; //*p 代表的就是一个int变量,只不过*p这个整型变量的内存分配方式和11的i的分配方式不同 free(p);//free(p)表示把p所指向的内存给释放掉 p本身是静态的, 不能有程序员手动释放,p本身的内存只能在p变量所在的函数运行终止是由系统自动释放 printf("好啊\n"); } 21 # include <stdio.h> # include <malloc.h> void f(int * q) { //* p = 200;//error //q = 300;//error //** p = 4304; //error * q = 200; //free(q) // 必须注释掉,否则,第二个printf会出现错误 } int main(void) { int * p = (int *)malloc(sizeof(int));//sizeof(int)返回值是int所占的字节数 * p = 10; printf("%d\n", * p); f(p); printf("%d\n", * p); return 0; } 22 # include <stdio.h> # include <malloc.h> int main(void) { int a[5]; //如果int占4个字节的话, 则本数组总共包含有20个字节, 每四个字节被当做了一个int变量来使用 int len; int * pArr; int i; //动态数组的构造一维数组 printf("请输入你要存放的元素的个数:"); scanf("%d", &len); pArr = (int *)malloc(4 * len);//本行动态了构造了一个一维数组,这一维数组的长度是len, 该数组名是pArr, 该数组的每个元素是int类型, 类似于pArr[len] //对一维数组进行操作, 如:对动态一维数组进行赋值 for(i = 0; i < len; i ++) scanf("%d", &pArr[i]); //对一维数组的内容进行输出 printf("一维数组的内容是:\n"); for(i = 0; i < len; i ++) printf("%d\n", pArr[i]); //free(pArr); //释放掉动态分配的数组 //补充:pArr当初是指向50个字节,当执行realloc(pArr, 100); pArr指向了100个字节 return 0; } 23 //多级指针 # include <stdio.h> int main(void) { int i = 20; int * p = &i; int ** q = &p; int ***r = &q; //r = &p; //error printf("i = %d\n", ***r); return 0; } 24 # include <stdio.h> void f(int ** q) { //*q 就是p } void g() { int i = 10; int * p = & i; f(&p); // p是int类型, &p就是int **类型 } int main(void) { g(); return 0; } 25 # include <stdio.h> void f(int ** q) { int i = 5; //*q 等价于p q和**q都不等价于p //*q = i;//error 因为*q = i; 等价于p = i; 这样写是错误的 *q = &i; // p = &i; } int main(void) { int * p; f(&p); printf("%d\n", * p); //本语句语法没有问题, 但逻辑上有问题 return 0; } 26 //动态内存可以跨函数使用 # include <stdio.h> # include <malloc.h> void f(int ** q) { * q = (int *)malloc(sizeof(int)); //* q = 5;// p = 5; //q = 5;//error; ** q = 8;//* p = 8; } int main(void) { int * p; f(&p); printf("%d\n", * p); }
浙公网安备 33010602011771号