红叶何时落水
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
#if 0
//告诉编译器该如何翻译这个指针 void* 百搭,自动转换
char *s = "abcd";//char 是来形容该指针的指向的类型,而指针变量的类型是固定的
char **s2 = &s;
printf("sizeof(s) = %d s = %s\n", sizeof(s), s);
printf("sizeof(s2) = %d *s2 = %s\n", sizeof(s2), *s2);
int i = 1;
int *p = &i;
unsigned int *p2 = &p;
printf("p = %p\n", p);
printf("&p = %p\n", &p);
printf("*p2 = %p\n", *p2);
//printf("**p2 = %x\n", *(*p2));//没法使用,多级指针的意义所在,不可以链表的形式实现多级指针
int *P_null = NULL;//空指针,为了防止野指针(没有初始化的指针)
printf("P_null = %p\n", P_null);
#endif
#if 0
//指针与数组
int arr[3] = {1,2,3};
int *p = arr;
//注意p++与p+1;p++很危险p为左值;p+1中为右值
printf("*(arr + 0) = %d\n", *(arr + 0));
printf("p[0] = %d\n", p[0]);//注意p[0]与arr[0]本质区别,arr是常量(ROM),p是变量(RAM)
printf("p[0] = %d\n", (p+1)[0]);//=>arr[1] == 2
printf("*p = %d *p++ = %d\n", *p, *p++);
printf("*p = %d *p++ = %d\n", *p, *p++);
printf("*p = %d *p++ = %d\n", *p, *p++);//由此可以看出,printf的参数执行是从右边开始的
int *p2 = (int [3]){1,4,3} + 1;//没毛病
int *p3 = p2 - 1;
int y = ++(*--p2);//*p返回的是一个左值,因为*p = 2;成立可以再次赋值
printf("y = %d\n", y); // y = *(p2 - 1) + 1;
printf("p3[0] = %d\n", p3[0]);// 上面的 ++ 将 *(p2 - 1) 由 1 => 2 这就是说那个式子里有三个左值 y p2 *(p2 - 1)
#endif
#if 0
//指针与二维数组
int arr[2][3] = {{1,2,3},{4,5,6}};
int *p = arr;//这种情况不可以,该式右值的属性与左值属性不同,一个是数组,一个是指针
printf("sizeof(arr) = %d\n", sizeof(arr));
printf("sizeof(arr[0]) = %d\n", sizeof(arr[0]));
printf("arr = %p\n", arr);
printf("arr+1 = %p\n", arr + 1);
printf("p = %p\n", p);
printf("p + 1 = %p\n", p + 1);//以上是指针与数组的区别
printf("**(arr + 1) = %d\n", **(arr + 1));//指针降级
printf("*(arr + 1) = %p\n", *(arr + 1));//指针降级
printf("arr + 1 = %p\n", arr + 1);//指针降级
printf("*arr + 1 = %p\n", *arr + 1);//指针降级,添加"*"后,数组名会变成指针的方式访问内存
int *p2 = *arr;//合理,加“*”降级为普通指针类型访问内存
printf("*p2 = %d\n", *p2);
printf("*(p2 + 1) = %d\n", *(p2 + 1));
printf("*p2[4] = %d\n", p2[4]);
#endif
#if 0
//数组指针
int (*p)[3];//=>int[3] *p; p+1的存储移动为int*3
int arr[2][3] = {{1,2,3}, {4,5,6}};
p = arr;//注意,虽然p访存方式和arr一致,但是arr是地址常量,p是指针变量
printf("arr + 1 = %p\n", arr + 1);
printf("p + 1 = %p\n", p + 1);
printf("**(p + 1) = %d\n", **(p + 1));//"*"指针访存方式降级
printf("**(arr + 1) = %d\n", **(arr + 1));
#endif
#if 0
//字符数组
char *str_p = "hello";//注意"hello"是一个字符串,他储存在ROM区,是只读的,而RAM区的指针指向"hello"所在的地址,从ROM中访存读取,不可以再次修改
char str_arr[] = "world";//数组则是在RAM的栈中开辟了一块空间,可读可写
printf("sizeof(str_arr) = %d strlen(str_arr) = %d\n", sizeof(str_arr), strlen(str_arr));//数组大小
printf("sizeof(str_p) = %d strlen(str_p) = %d\n", sizeof(str_p), strlen(str_p));//指针大小//区别一
//区别二 这里的指针中所存储的地址是只读的,而数组名代表的那个地址是可读可写的
strcpy(str_arr, "hello world");//可以成功赋值
puts(str_arr);
// strcpy(str_p, "hello world");//出错,无法修改ROM区段
// puts(str_p);
strcpy(&str_p, "hello world");//当然,这样可以,因为&str_p所代表的地址位于RAM,
puts(&str_p);//这里也反映了C语言的危险性,这里毁掉了str_p这个指针,同时已发生了内存溢出
//上面那个例子仅仅是为了区分ROM地址与RAM地址,无任何使用以及操作正确性
#endif
#if 0
//const访存修饰符 先修饰左边,后修饰右边,只能修饰一个
//#define的数据是存在于指令中的,而const是要占用ROM的
//当变量处于函数中,它储存在栈空间,可以通过地址指针间接改变
const float PI = 3.14;
float *p = &PI;
*p = 3.1415;
printf("PI = %f\n", PI);
//常量指针 const int *p;或int const *p; *p不可以变化 p可以重新赋值(指向新地址)
//指针常量 int *const p; *p可以变化,p不可以变化
//注 keil环境
// float PI_font = 1;//经过验证,const为局部变量的话,是处于栈空间,但是编译器禁止将他的地址赋值给指针,
// //尽管间接改变了他地址上的值,依旧不影响程序,应该是程序将其以宏定义的方法进行了优化
// const float PI = 3.14;
// float *p = &PI_font;
// p--;
// *p = 3.1415;
// printf("&PI = %p PI = %f \n p = %p *p = %f\n", &PI, PI, p, *p);//&PI = 2000c9f8 PI = 3.140000
// //p = 2000c9f8 *p = 3.141500
// static const int PI = 3;//&PI = 08005308 PI = 3 加上static就定义到了FLASH区
// printf("&PI = %p PI = %d\n", &PI, PI);
#endif
#if 0
//数组指针(指向数组的指针int (*p)[3] => int[3] *p) 常量指针(指向常量的指针) 函数指针(指向函数的指针)
//指针数组 int* arr[3]; 存放指针的数组,数组元素是指针 arr依旧是一个地址常量,上面的那三个是指针变量
int *arr_p[3];
int i = 1;
int j = 3;
char *str_arr_p[3] = {"word1", "word2", "word3"};
arr_p[0] = &i;
arr_p[1] = &j;
puts(str_arr_p[0]);
puts(str_arr_p[1]);
puts(str_arr_p[2]);
printf("*arr_p[0] = %d\n", *arr_p[0]);
printf("*arr_p[1] = %d\n", *arr_p[1]);
#endif
#if 1
//多级指针 *相当于升级,取该地址的值,&相当于降级,取该值的地址,添加一个“*”,就是升一级,少一个“*”就降一级, 初始化中的星号用来说明他最高有几级
int **p;//=> int** p;在初始化赋值时,是赋值给p,而非*p,或**p,
// &左值 得到一个地址右值
// *左值/右值 得到一个左值 可以存放新的右值
int *p1;
int i = 3;
int j = 5;
p = &p1;
p1 = &i;
printf("**p = %d *p = %p p = %p\n*p1 = %d &p1 = %p &i = %p\n", **p, *p, p, *p1, &p1, &i);
*p = &j;
printf("*p1 = %d\n", *p1);
#endif
return 0;
}