C高级——指针

一、了解指针

        指针是C语言的灵魂 。指针的本质就是一个直接访问内存的工具,在众多语言中只有C语言有指针。   


        1、指针共有两个含义: 
            ①、指针变量 ,也可通俗是了解为一个变量存放了一个内存的地址 ;  
             ②、一个内存地址指针常量 。

        2、指针变量的定义: 

                                        存储类型  指针指向的空间的数据类型 *  变量名;
eg:   int *p = &a;   //定义一个名为p的指针并把变量a的地址赋值给p

        3、指针变量的赋值:  类型匹配才可以赋值 
    物理意义: 与指定的内存  建立联系 

取(&)地址运算: 得到变量的内存地址   

野指针:  一个指针  指向的内存 不可知 或  不确定 或  非法(不可访问) 
空指针:  一个指针  指向内存 0地址  即这个指针中的值是0   int *p = NULL;
宏 NULL 空指针   (void *) 0

void * 类型 : 表示 万能指针, 一个可以指向 任意类型的指针 

指针的访问:  * 指针取值运算符 
   *指针变量  即等同于 指针指向的目标(对象)

int b;
int *p = &b;
*&b; 等同于 b 
      * 是 & 的逆运算 
&*p; 等同于 &b
      & 是 * 的逆运算

#include <stdio.h>

int a =5;
int main()
{

	int b;
	int *p = &a; //定义一个指针变量并初始化
	int **pp = &p;
	int *x;  // 野指针
	x = NULL;// 空指针
	//指针的表示
	printf("&a=%p\n",&a);
	printf("p= %p\n",p); // 打印变量p中存放的地址
	p = &b; //给p赋值
	printf("p= %p\n",p); // 打印变量p中存放的地址
	printf("&p=%p\n",&p); // 打印变量p的地址	
	printf("pp=%p\n",pp); // 打印变量pp中存放的地址	
//指针的访问
	*p = 20; //*p 等同于b *p = 20;  等同于 b = 20;  给*p赋值
	printf("b=%d\n",b);
	printf("*p=%d\n",*p);

	printf("**pp=%d\n", **pp); // **pp 等同于 *p 等同于b
	printf("*pp=%p\n", *pp);  // *pp 等同于p 
	printf("*&b=%d\n",  *&b ); 
	printf("&*p=%p\n",  &*p ); 
	//空指针
	//int *q = NULL;
	//printf("%d",*q);  段错误
	//void * 
	void *q = p;
	printf("q=%p\n",q);
	//printf("*q=%d\n",*q); //语法错误,无法编译
	printf("*(int*)q=%d\n",*(int*)q); //
	return 0;
}



二、指针的算数运算

 
    1、指针 + 或 - 一个整数  ,其结果仍然是一个指针 
        其运算本质就是  地址的移动 + 向大地址方向移动  - 小地址方向移动 
        其移动的字节大小  由其指向的类型长度决定  +1 / -1 移动一个指向的类型 
    指针的 ++ -- 运算

#include <stdio.h>
//指针的算数运算
int main()
{
	int a= 10;
	int *p = &a;

	printf("p  =%p\n",p);
	printf("p+1=%p\n",p+1);
	printf("p+2=%p\n",p+2);
	printf("p-1=%p\n",p-1);
	
	char b;
	char *q = &b;
	printf("q  =%p\n",q);
	printf("q+1=%p\n",q+1);
	printf("q+2=%p\n",q+2);
	printf("q-1=%p\n",q-1);
	
	//printf("*(q-1)=%d\n",*(q-1));
	
	//指针与数组
	int arr[5] = {1,2,3,4,5};
	//p = &arr[0]; //p指向arr的0号元素
	p = arr;  // arr数组首地址 int *  &arr[0]
	
	//遍历数组
	for(int i = 0; i< 5; i++)
	  printf("%d ",p[i]);
	printf("\n");
	
	for(int i = 0; i< 5; i++)
	  printf("%d ",*(arr+i));
	printf("\n");

	//p = arr;
	//	arr = p; 不能进行该操作 arr数组名是一个常量指针  

	return 0;
}



    


   三、 指针 与 指针的 运算 


    1. 大地址 - 小地址  结果是一个整数其大小为 这两个地址之间相隔的 指向的类型个数 
    
    2. 关系运算   本质是 判断这个两个地址在内存中的位置  
    p  >  q   p地址 在 q地址的 大方向  
    p  <  q   p地址 在 q地址的 小方向
    p ==  q   p和q指针指向同一个内存 
    p !=  q   p和q指针指向不同的内存 
    p  >= q   p地址 在 q地址的 大方向  或 相同
    p  <= q   p地址 在 q地址的 小方向  或 相同
    


四、一级指针和一维数组


    数组名可以当指针用 
    指针变量 可以做数组用 
    区别在于  指针变量 可以重新赋值   而数组名不行 
    int arr[5] = {1,2,3,4,5};
    int *p = arr; // p = &arr[0]  等同 
    p[0]  == arr[0]  == *arr  == *p    //等同 
    p[1]  == arr[1]  == *(arr+1)  == *(p+1)
    
练习:  用指针方式遍历数组  写函数实现

void show_arr(int *arr, int len)   //要求使用arr和len完成遍历 不再定义其他变量
{
    while(len--) printf("%d ",*(arr++));
}

//*arr++   ==  *(arr++)  ==  先*arr用  然后 arr=arr+1; 

int main()
{
    int arr[] = {1,2,3,4,5};
    show_arr(arr,5);
    return 0;
}

有如下定义:
int a[10]={0,1,2,3,4,5};
int *p = a;
假设每个表达式中p=a;求表达式代表的值?
*p=?    a[0]   == 0 
*a=?    a[0]   == 0
p[0]=?  a[0]   == 0 
a[0]=?  
*p++=?  ==  *(p++) == 先*p用 作为表达式的值, 然后 p=p+1
*(p++)=?
*p+1=?     a[0] + 1 == 1
*(p+1)=?   a[1]  == 1
*a+1=?     a[0] + 1 == 1
*(a+1)=?   a[1]  == 1

练习: 数组倒叙 

void arr2rra(int *start, int *end)   //倒叙 从start到end之间的 数组元素, 不能定义其他变量
{

}
int main()
{
    int arr[] = {1,2,3,4,5};
    show_arr(arr,5);
    arr2rra(arr, arr+4);
    show_arr(arr,5);
    return 0;
}

五、指针与字符串

char s[] = "hello";  //s是一个数组 将"hello"复制一份到s数组中

cosnt char *p = "hello";  // p是一个指针变量 指向常量区字符串 

练习:求字符串的长度

int len(const char *s)
{
    char *p = s;
    while(*p) p++;
    return p-s;
}

注:const 修饰指针
    cosnt char  *p;              *p 只读   p 可读可写 
    char * const p;              *p 可读可写  p 只读 
    const char * const p ;      *p 只读   p 只读 


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值