指针1月29~1月30日学习笔记(最有含金量的一集!)

什么是指针?

指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。

不同语境下的指针:

1.定义一个指针,是指定义一个变量,数据类型是指针类型,这个变量里面存放地址,也就是内存单元的编号。

2.打印某个变量的指针,此时指针指的是地址

变量的指针就是变量的存储地址,指针变量就是存储指针的变量。

基类型* 指针变量名;

基类型 --- 数据类型
           //基本数据类型 
           //数组类型 
           //基类型 表示 指针变量 指向的目标的 数据类型 

指针变量初始化时,最好赋值“NULL”或“0”,用来防止野指针出现,如果赋值“0”,此时的“0”含义并不是数字“0”,而是 NULL 的字符码值。

指针变量再内存中的大小:在64位系统中占8字节,在32位系统中占4字节。

指针的核心功能:被调修改主调 
1.想修改谁,就把谁的地址传过去 
2.必须要做*运算(间接访问),实现修改 

指针的运算

取地址运算符&:单目运算符&是用来取操作对象的地址。例:&i 为取变量 i 的地址。对于常量表达式、寄存器变量不能取地址(因为它们存储在存储器中,没有地址)。
指针运算符*(间接寻址符):与&为逆运算,作用是通过操作对象的地址,获取存储的内容。例:x = &i,x 为 i 的地址,*x 则为通过 i 的地址,获取 i 的内容。

 &和* 的优先级相同,结合性自右向左。

  • *&p 表示对指针 p 解引用后再取其地址。也就是说,首先 *p 表达式会获取 p 指向的值,然后 & 运算符获取该值的地址。结果是对指针 p 自身的地址取值,类型仍然是指向 p 的指针。当p不是指针类型的变量时,此时*&抵消掉了。

  • &*p(p必须是指针) 表示对指针 p 解引用后再取其地址。与上面的情况不同的是,对 *p 解引用后直接获取的是 p 指向的内容,然后 & 运算符获取这个内容的地址。结果是一个新的指针,指向跟 p 指向的内容相同。

//声明了一个普通变量 a
int a;
//声明一个指针变量,指向变量 a 的地址
int *pa = NULL;
//通过取地址符&,获取 a 的地址,赋值给指针变量
pa = &a;
//通过间接寻址符,获取指针指向的内容
printf("%d", *pa);

  *p 过程
 1.首先拿出p指针变量中的值(地址) 到内存中定位 
 2.从定位处开始,偏移出sizeof(基类型)大小的一块空间 
 3.把这块空间当做一个 基类型的 变量来看  

  int *p,q; //p是指针变量  q是int型变量

可以对指针进行四种算术运算:++、--、+、-

 p-q  
     前提: 同一类型的指针 
     表示之间差了几个基类型   常用在数组中
 p+q  //指针不能做加法运算  

p+1  //指向了下一个一基类型的数据

 

  1. 指针变量的自增自减运算。指针加 1 或减 1 运算,表示指针向前或向后移动一个单元(不同类型的指针,单元长度不同)。这个在数组中非常常用。
  2. 指针变量加上或减去一个整形数。和第一条类似,具体加几就是向前移动几个单元,减几就是向后移动几个单元。

打印某个变量的地址  %p

#include 

int main() {
    int num = 42;
    printf("变量 num 的地址是:%p\n", &num);

    return 0;
}

指针的关系运算

  1. 相等性比较 (==):比较两个指针是否指向同一个对象或地址。

  2. 不等性比较 (!=):比较两个指针是否不指向同一个对象或地址。

  3. 大小关系比较 (<<=>>=):比较两个指针所指向的地址大小。

#include 

int main() {
    int num1 = 42;
    int num2 = 88;

    int* ptr1 = &num1;
    int* ptr2 = &num2;
    int* ptr3 = &num1;

    if (ptr1 == ptr2) {
        printf("ptr1 和 ptr2 指向相同的对象\n");
    } else {
        printf("ptr1 和 ptr2 指向不同的对象\n");
    }

    if (ptr1 != ptr2) {
        printf("ptr1 和 ptr2 指向不同的对象\n");
    } else {
        printf("ptr1 和 ptr2 指向相同的对象\n");
    }

    if (ptr1 == ptr3) {
        printf("ptr1 和 ptr3 指向相同的对象\n");
    } else {
        printf("ptr1 和 ptr3 指向不同的对象\n");
    }

    if (ptr1 < ptr2) {
        printf("ptr1 的地址位于 ptr2 之前\n");
    } else {
        printf("ptr1 的地址位于 ptr2 之后\n");
    }

    return 0;
}

 指针与数组

在数组中,数组名即为该数组的首地址,且数组名本身就是一个指针常量。结合上面指针和整数的加减,我们就可以实现指针访问数组元素。

数组名不等价于指针变量,指针变量可以进行 p++和&操作,而这些操作对于数组名是非法的。数组名在编译时是确定的,在程序运行期间算一个常量

 通过指针访问到数组元素:
  *(p+i) <=> int型的变量   <=> a[i] <=>p[i]<=> *(a + i)   ,i是偏移量

逆序

指针1月29~1月30日学习笔记(最有含金量的一集!)_第1张图片

使用指针迭代的方法实现二分查找

指针1月29~1月30日学习笔记(最有含金量的一集!)_第2张图片

用递归的方法实现二分查找

指针1月29~1月30日学习笔记(最有含金量的一集!)_第3张图片

使用指针迭代的方法分别实现选择、冒泡、插入排序

指针1月29~1月30日学习笔记(最有含金量的一集!)_第4张图片

指针1月29~1月30日学习笔记(最有含金量的一集!)_第5张图片

指针1月29~1月30日学习笔记(最有含金量的一集!)_第6张图片

快速排序

指针1月29~1月30日学习笔记(最有含金量的一集!)_第7张图片

注意:第二三步不能反过来

指针1月29~1月30日学习笔记(最有含金量的一集!)_第8张图片

指针1月29~1月30日学习笔记(最有含金量的一集!)_第9张图片

用指针实现strlen 、strcat、 strcpy和 strcmp函数

size_t Strlen(const char *s)
{
	int cnt = 0;
	while (*s!='\0')
	{
		cnt++;
		++s;
	}

	return cnt;
}

char * Strcat(char *dest, const char *src)
{
	char *ret = dest;

	while (*dest != '\0')
		dest++;

	while((*dest = *src) != '\0')
	{
		dest++;
		src++;
	}

	return ret;
}

char *Strcpy(char *dest,const char *src)
{
	char *ret = dest;

	while (*dest = *src)
	{
		dest++;
		src++;
	}

	return ret;
}

int Strcmp(const char *s1,const char *s2)
{
	while (*s1==*s2 && *s1!='\0' && *s2 != '\0')
	{
		++s1;
		++s2;
	}

	return *s1 - *s2;
}

const 关键字

 “const” 关键字可以让编译器确保程序中的常量不被修改,从而提高代码的可读性和安全性。

const int *p = &a;   和int const *p = &a;  的意义一样  都是表示 基类型 为只读 

int *const p = &a;  //限定p为只读 
const int * const p = &a;  //p不能被修改,指向的目标类型不能被修改 
                                        //(是不能通过*p) 

char *p="world"; 和 char *q = "world";

在内存中的地址一样, 因为他们存储在字符常量区

而 chars[ ] ="world";  和他们不一样  存储在栈区

const char * p 可以用来保存字符串常量的地址  

#include 

int main() {
    const char * p = "Hello, World!"; // 声明一个指向字符串常量的指针

    printf("%s\n", p); // 输出字符串常量内容

    return 0;
}

 

你可能感兴趣的:(学习,笔记)