一、内存含义数组
二、内存是沟通CPU与硬盘的桥梁ide
三、物理存储器和存储地址空间函数
四、物理存储器:实际存在的具体存储器芯片编码
五、存储地址空间:对存储器编码的范围。咱们在软件上常说的内存是指这一层含义spa
六、内存地址操作系统
七、内存中的每个数据都会分配相应的地址指针
注:windos电脑在作数据存储时采用小端对齐。blog
注:Linux 电脑在作数据存储时采用大端对齐。排序
注意:&能够取得一个变量在内存中的地址。可是,不能取寄存器变量,由于寄存器变量不在内存里,而在CPU里面,因此是没有地址的。
注意:&是取地址符号是升维度的、*是取值符号是将维度的。
注意:在定义指针类型必定要和变量的类型对应上。内存
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 定义指针变量存储变量地址 int a = 10; // 指针类型:数据类型* int* p; p = &a; // 经过指针间接改变变量的值 *p = 100; printf("%p\n", &a); printf("%p\n", p); printf("%d\n", a); printf("%d\n", *p); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { char ch = 'a'; char* p = &ch; // 全部指针类型存储都内存地址,内存地址都是一个无符号十六进制整形数 // 32位操做系统全部指针类型:内存占用4字节 // 64位操做系统全部指针类型:内存占用8字节 printf("%d\n", sizeof(int*)); printf("%d\n", sizeof(char*)); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; // P 和 arr 不一样点 // 指向数组指针 int* p = arr; // 相同点 //p[i] //*(p+i) // 不一样点 // p 是变量、arr是常量 // p 是一个指针4个字节大小 // arr 是一个数组是40个字节大小 printf("指针类型大小%d\n", sizeof(p)); printf("数组大小%d\n", sizeof(arr)); // 数组做为函数参数会化为指针、丢失数组的精度 // 经过 int* 将指针变为值 // void BubbleSort(int arr[]) // void BubbleSort(int* arr[],int len) return 0; }
指针变量也是变量,是变量就能够任意赋值,不要越界便可(32位为4字节,64位为8字节),可是,任意数值赋值给指针变量没有意义,由于这样的指针就成了野指针,此指针指向的区域是未知(操做系统不容许操做此指针指向的内存区域)。因此,野指针不会直接引起错误,操做野指针指向的内存区域才会出问题。野指针和有效指针变量保存的都是数值,为了标志此指针变量没有指向任何变量(空闲可用)
int a = 100; int *p; p = a; //把a的值赋值给指针变量p,p为野指针, ok,不会有问题,但没有意义 p = 0x12345678; //给指针变量p赋值,p为野指针, ok,不会有问题,但没有意义 *p = 1000; //操做野指针指向未知区域,内存出问题,err
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 野指针 -> 指针变量指向一个未知的空间 // 不建议将一个变量的值直接赋值给指针 // 程序中容许存在野指针 int* p = 100; // 操做系统将0-255做为系统占用不容许访问操做 // 操做野指针对应的内存空间可能报错 printf("%d\n", *p); return 0; }
C语言中,能够把NULL赋值给此指针,这样就标志此指针为空指针,没有任何指针。
// 空指针 int *p = NULL; // NULL是一个值为0的宏常量: #define NULL ((void *)0)
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 空指针是指内存地址编号为0的空间 int* p = NULL; // 操做空指针对应的空间必定会报错 *p = 100; printf("%d\n", *p); // 空指针能够用做条件判断 if (p == NULL) { } return 0; }
void *指针能够指向任意变量的内存空间。
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { int a = 10; // 万能指针能够接受任意类型变量的内存地址 void * p = &a; // 再经过万能指针修改变量的值时,须要找到变量对应的指针类型 *(int*)p = 100; printf("%d\n", a); printf("%d\n", *(int*)p); // printf("万能指针在内存占得字节大小:%d\n", sizeof(void*)); return 0; }
const 修饰能够约束指针类型或值得修改,但使用+1级别指针也可让const无效。
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 一、 // 常量:不容许修改 // 存储空间:栈区(可指针间接修改) const int a = 10; // 指针间接修改常量值 int* p = &a; *p = 100; printf("%d\n", a); // 二、 // const 修饰指针类型(内存空间) int a = 10; int b = 20; const int* p = &a; // 能够修改指针变量的值 // 不能够修改指针内存空间的值:*p = 100; p = &b; printf("%d\n", *p); // 三、 // const 修饰指针变量 int c = 10; int d = 20; int* const p = &c; // 能够修改指针类型(内存空间)的值 // 不能够修改指针内存空间的值:p = &d; *p = 100; printf("%d\n", *p); // 四、 // const 修饰指针变量、类型(内存空间) // 只读指针 int e = 10; int f = 20; // 不能够修改指针内存空间的值:*p = 100; // 不能够修改指针内存空间的值:p = &f; const int* const p = &e; // 二级指针操做 // 可经过二级指针修改一级指针内存空间的值: int** pp = &p; // *pp是一级指针的值(内存空间) *pp = &b; // **pp是变量的值、**表明将了一个维度 **pp = 100; printf("%d\n", *p); return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { //const修饰一个变量为只读 const int a = 10; //a = 100; //err //指针变量, 指针指向的内存, 2个不一样概念 char buf[] = "aklgjdlsgjlkds"; //从左往右看,跳过类型,看修饰哪一个字符 //若是是*, 说明指针指向的内存不能改变 //若是是指针变量,说明指针的指向不能改变,指针的值不能修改 const char *p = buf; // 等价于上面 char const *p1 = buf; //p[1] = '2'; //err p = "agdlsjaglkdsajgl"; //ok char * const p2 = buf; p2[1] = '3'; //p2 = "salkjgldsjaglk"; //err //p3为只读,指向不能变,指向的内存也不能变 const char * const p3 = buf; return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 定义int类型 const int a = 10; // 直接不能够修改 // a = 100; //err // 经过一级指针修改 int* p = &a; *p = 100; // 定义char类型 char ch1[] = "hello"; char ch2[] = "hello"; // 指向常量指针:能够修改指针变量的值、不能够修改指针变量指向内存空间的值 const char* p = ch1; // *p = 'm';//err // p = ch2;//ok // p[2] = 'm';//err // 定义char类型 char ch3[] = "hello"; char ch4[] = "hello"; // 常量指针:能够修改指针变量指向内存空间的值、不能够修改指针变量的值 char* const p = ch3; // p = ch4;//err // p[2] = 'm';//ok // *(p + 2) = 'm';//ok // 定义char类型 char ch5[] = "hello"; char ch6[] = "hello"; // 不可修改变量与内存 const char* const p = ch5; // p = ch6;//err // p[2] = 'm';//err // *p = 'm';//err // 二级指针 char** p1 = &p; // *p1 = ch2;//ok // *(*p1+1) = 'm';//ok return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; // 数组名是一个常量 不容许赋值 // 数组名是数组首元素地址 // aar = 100; //err // 建立指针变量 int* p; p = arr; printf("%p\n", p); // 打印数组第一个值 printf("%d\n", *p); printf("%p\n", arr); // *取值(arr内存地址+1) 、至关于arr[1] printf("%d\n", *(arr + 1)); // 指针类型变量+1:等同于内存地址+sizeof(类型) printf("%d\n", *(p + 1)); // 指针p++:等同于内存地址+sizeof(类型) *p = 123; p++; printf("%p\n", arr); printf("%p\n", p); for (int i = 0; i < 10; i++) { // 打印数组值 printf("%d\n", p[i]); printf("%d\n", *(p + i)); // 打印数组值 printf("%d\n", *p++); } // 两个指针相减 获得的结果是两个指针的偏移量(步长) // 全部的指针类型 相减结果都是int类型 // 3c 40 +1 至关于 sizeof(int) 40/sizeof(int) int step = p - arr; printf("%d\n", step); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> // 方式一:数组方式实现 void my_strcpy01(char* dest, char* ch) { int i = 0; // 非0为真值 while (ch[i]) { dest[i] = ch[i]; i++; } dest[i] = 0; } // 方式二:以指针偏移量 void my_strcpy02(char* dest, char* ch) { int i = 0; while (*(ch+i)) { *(dest + i) = *(ch + i); i++; } *(dest + i) = 0; } // 方式三:以指针运算方式实现 void my_strcpy03(char* dest, char* ch) { while (*ch) { *dest = *ch; // 指针+1至关于指向数组下一个元素 内存地址变化了sizeof(char) dest++; ch++; } *dest = 0; } // 方式四:以指针加运算方式实现 void my_strcpy04(char* dest, char* ch) { // 第一步:*ch 取值 *dest 取值 // 第二部:*dest = *ch 赋值 // 第三部:判断 值是否非0 // 第四部:ch++ dest++ while (*dest++ = *ch++); } int main(void) { // 指针运算、字符串拷贝 char ch[] = "hello world"; char dest[100]; my_strcpy04(dest, ch); printf("%s\n", dest); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; int* p = arr; // 指针的加减运算和指针的类型有关 p = &arr[3]; p--; p--; p--; // 内存地址相差:12 / sizeof(int) = 偏移量 int step = p - arr; // 指针操做数组时下标容许时负数 // p[-2] = *(p-2); printf("%d\n", p[-2]); printf("%p\n", p); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 指针和运算符的操做 int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; int* p = arr; // 野指针 // p = p + arr; //err // p = p*arr; //err // p = p*4; //err // p = p/4; //err // p = p%4; //err // 指针判断可使用、> = < ? && || ... // p = &arr[3] // if (p > arr) { printf("真\n");} // 野指针能够相减 // p = 100; // int step = arr - p; ///printf("%d\n",step) return 0; }
指针数组,它是数组,数组的每一个元素都是指针类型。
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 定义数组 数据类型 数据名[元素个数] = {值1,值2} // 定义指针数组 int a = 10; int b = 20; int c = 30; int* arr[3] = { &a,&b,&c }; // arr[0]:为指针数组地址 // *arr[0]:为指针对应值 printf("%d\n", arr[0]); printf("%d\n", *arr[0]); for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) { // 打印数组内每一个值 printf("%d\n", *arr[i]); } // 指针数组大小 = 对应类型 * 元素个数 printf("指针数组大小:%d\n", sizeof(arr)); printf("指针数组大小:%d\n", sizeof(arr[0])); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 指针数组里面元素存储的是指针 int a[] = { 1,2,3 }; int b[] = { 4,5,6 }; int c[] = { 7,8,9 }; // 指针数组时一个特殊的二维数组模型 // 指针数组对应于二级指针 int* arr[] = { a,b,c }; // 打印内存地址 // arr 是指针数组的首地址 printf("%p\n", arr[0]); printf("%p\n", a); printf("%p\n", &a[0]); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { // 经过二维数组方式打印全部值 printf("%d", arr[i][j]); // 经过偏移量方式打印 printf("%d", *(arr[i]+j)); // 经过偏移量与指针运算方式打印 printf("%d", *(*(arr + i) + j)); } puts(""); } return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> // 数组名作函数参数,函数的形参会退化为指针 // 经过数组写法实现 void my_strcat01(char* ch1, char* ch2) { int i = 0; while (ch1[i] != '\0') { i++; } int j = 0; while (ch2[j] != '\0') { ch1[i + j] = ch2[j]; j++; } ch1[i + j] = 0; } // 经过指针加偏移量方式实现1 void my_strcat02(char* ch1, char* ch2) { int i = 0; while (ch1[i] != '\0') { i++; } int j = 0; while (*(ch2 + j) != '\0') { *(ch1 + i + j) = *(ch2 + j); j++; } ch1[i + j] = 0; } // 经过指针加偏移量方式实现2 void my_strcat03(char* ch1, char* ch2) { while (*ch1)ch1++; while (*ch1++ = *ch2++); } int main(void) { char ch1[100] = "hello"; char ch2[] = "world"; my_strcat02(ch1, ch2); printf("%s\n", ch1); return 0; }
int a = 10; int *p = &a; //一级指针 *p = 100; //*p就是a int **q = &p; //*q就是p //**q就是a int ***t = &q; //*t就是q //**t就是p //***t就是a
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { int a[] = { 1,2,3 }; int b[] = { 4,5,6 }; int c[] = { 7,8,9 }; int* arr[] = { a,b,c }; // 指针数组和二级指针创建关系 int** p = arr; // 对应:arr[0][0]、a[0] printf("%d\n", **p); // 二级指针加偏移量:至关于跳过了一个觉得数组大小 // 一级指针加偏移量:至关于跳过了一个元素 //对应:arr[0][1]、a[1] printf("%d\n", *(*p+1)); //对应:arr[1][1]、b[1] printf("%d\n", *(*(p + 1) + 1)); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { // 经过偏移量与指针运算方式打印 printf("%d", *(*(arr + i) + j)); } puts(""); } return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { //*ppp==**pp==&p //**ppp==*pp=p==&a //***ppp==**pp==*p=a int a = 10; int b = 20; int* p = &a; int** pp = &p; int*** ppp = &pp; // pp:二级指针变量的值 // *pp:一级指针的值 // **pp:变量的值 // 等价于:p=&b // *pp = &b; // 等价于:a = 100 //**pp = 100; // 野指针 // *p = 100; printf("%d\n", *p); return 0; }
字符指针经过指针处理字符
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 栈区字符串 char ch[] = "hello world"; // 数据区常量区字符串、不容许修改内容 // hello world 对应内存地址为只读,大小相同 char* p = "hello world"; char* p1 = "hello world"; // ch[2] = 'm'; // 可修改 // p[2] = 'm'; //err return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 样式一 // 能够作修改 // 指针数组 char ch1[] = "hello"; char ch2[] = "world"; char ch3[] = "dabaobei"; char* arr1[] = { ch1,ch2,ch3 }; // 样式二 // 不能作修改、但能够排序 // 字符串数组 char* arr2[] = { "hello","wojjrld","zzzzz" }; // 字符串排序 for (int i = 0; i < 3 - 1; i++) { for (int j = 0; j < 3 - 1 - i; j++) { // 找首字符进行比较 if (arr2[j][0]>arr2[j + 1][0]) { // 交换指针数组进行排序 char* temp = arr2[j]; arr2[j] = arr2[j + 1]; arr2[j + 1] = temp; } } } // 打印 for (int i = 0; i < 3; i++) { printf("%s\n", arr2[i]); } return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> // 数组实现 int my_strlen01(char* ch) { // 计算字符串有效长度 int i = 0; while (ch[i] != '\0')i++; return i; } // 指针实现 int my_strlen02(char* ch) { char* temp = ch; while (*temp != '\0')temp++; return temp - ch; } int main(void) { char ch[] = "hello world"; int len = my_strlen02(ch); printf("%d\n", len); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> // 指针做为函数参数传递 void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } int main(void) { int a = 10; int b = 20; // 值传递 // 形参不影响实参的值 // swap(a, b); // 地址传递 // 形参能够改变实参的值 swap(&a, &b); printf("%d\n", a); printf("%d\n", b); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> void remove_space(char* ch) { // 便利字符串有效个数 char* ftemp = ch; // 记录非空格字符串 char* rtemp = ch; while (*ftemp) { if (*ftemp != ' ') { *rtemp = *ftemp; rtemp++; } ftemp++; } *rtemp = 0; } int main(void) { char ch[] = " h e ll o w o r lld"; remove_space(ch); printf("%s\n", ch); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> // 数组方式 char* my_strchr01(char* str,char ch) { int i = 0; while (str[i]) { if (str[i] == ch) { return &str[i]; } i++; } return NULL; } // 指针方式 char* my_strchr02(char* str, char ch) { while (*str) { if (*str == ch) { return str; } str++; } return NULL; } int main(void) { char str[] = "hello world"; char* p = my_strchr02(str,'w'); if (p == NULL) { printf("未找到:"); } printf("%s\n", p); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> char* my_strchr(char* src, char* dest) { // 用于循环便利源字符串指针 char* fsrc = src; // 记录每次相同字符串首地址 char* rsrc = src; char* tdest = dest; while (*fsrc) { rsrc = fsrc; while (*fsrc == *tdest && *fsrc!='\0') { fsrc++; tdest++; } if (*tdest == '\0') { return rsrc; } // 回滚 // 目标字符串更新到起始位置 tdest = dest; fsrc = rsrc; fsrc++; } return NULL; } int main(void) { char src[] = "hello world"; char dest[] = "llo"; char* p = my_strchr(src,dest); printf("%s\n", p); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> // 数组实现 int getstrcount01(char* ch) { int i = 0; int count = 0; while (ch[i]) { if (ch[i] != ' ') { count++; } i++; } return count; } // 指针实现 int getstrcount02(char* ch) { int count = 0; while (*ch) { if (*ch != ' ')count++; ch++; } return count; } int main(void) { char ch[] = " hello world "; int len = getstrcount(ch); printf("%d\n", len); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { //97+26 ASCLL码 // 统计字符串出现次数 char ch[] = "helloworldfdjklfdjklfdsajklfdsa dsa"; // 存储字符串出现次数 int arr[26] = {0}; for (int i = 0; i < strlen(ch); i++) { // ASCLL码 a - 字符、++:每找到一个相同就+1 arr[ch[i] - 'a']++; } for (int i = 0; i < 26; i++) { if(arr[i]) printf("字母:%c出现次数:%d\n", i + 'a', arr[i]); } return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> // 数组实现 void inverse01(char* ch) { int i = 0; int j = strlen(ch) - 1; while (i < j) { char temp = ch[i]; ch[i] = ch[j]; ch[j] = temp; i++; j--; } return; } // 指针实现 void inverse02(char* ch) { char* ftemp = ch; char* btemp = ch + strlen(ch) - 1; while (ftemp<btemp) { char temp = *ftemp; *ftemp = *btemp; *btemp = temp; ftemp++; btemp--; } return; } int main(void) { char ch[] = "hello world"; inverse02(ch); printf("%s\n", ch); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int symm(char* ch) { char* ftemp = ch; char* btemp = ch + strlen(ch) - 1; while (ftemp < btemp) { if (*ftemp!=*btemp) { return 1; } ftemp++; btemp--; } return 0; } // 判断:回文字符串 int main(void) { char ch[] = "abcba"; int value = symm(ch); if (!value) { printf("相同\n"); } else { printf("不相同\n"); } return 0; }