指针的运用

一、指针的基础

1.指针的感念

(1)地址:内存单元的编号,指针就是地址,即指针就是内存单元编号

(2)指针也是一种数据类型,指针类型,专门用来处理地址数据

2.指针变量定义及引用

语法:

基类型 * 指针变量名

(1)基类型

数据类型 :整型、浮点型、字符型、指针类型、结构体类型 、函数类型

作用:表示该指针类型所指向的内存空间存放什么类型的数据

(2)*   //定义时表示此时定义的是一个指针类型的变量

(3)指针变量名  //符合标识符命名规则

int * p;    //pointer

int a = 10;  //a所在的空间是用来存放int类型数据的

float b = 10.0;

int *p = &a;

int *p = &b;//不可以,指针类型与b的数据类型不一致

&a  //表示获得a所在空间的首地址,表示获得了一块可以存放int类型数据的内存空间的地址

指针类型

int *p;   int * 整体叫指针类型

            int* 含义  首先表示一个指针类型,指向int型数据的指针类型

指针变量的引用

int a = 20;

int *p = &a  //p指向a,p中保存了a的地址

*  指针运算符为单目运算符,运算对象只能是指针(地址)

*p  表示访问p所指向的基类型的内存空间

*p 为间接访问,通过a访问的为直接访问

运算过程:(1)首先拿出p中的地址,到内存中定位(2)偏移出sizeof(基类型)大小的一块空间(3)将偏移处的这块空间,当做一个基类型来看(*p运算完的效果)

运行效果:相当于就是一个基类型的变量   *p<=>a

int a;

a的数据类型为int;&a的数据类型为int*(地址这种数据对应的数据类型为指针类型)

指针变量初始化

如果指针变量没有初始化,此时是随机值,称为野指针。初始化可以让指针变量有明确的指向

int a = 10;

int *p = &a;

int *p = NULL;  //NULL就是0号地址---空指针

//赋值:
int *p;

p = NULL;

int a;

int *p;

p = &a;

int *p,q;//p是指针类型int*,q是int型

int *p,*q  //此时表示定义了两个int*类型的变量p和q

注意:定义时候的*是修饰变量名的,表示定义的是一个指针类型的变量

指针的用途:指针可以实现被调修改主调

使用方法:(1)要修改谁,就把谁的地址传过去(2)被调函数中,一定要有对应的*p运算(3)传过去的实参地址,一定要对应一块有效的内存空间

#include<stdio.h>

int addOne (int *n)
{ 
    *n = *n + 1;
    return *n;
}
int main(void)
{
     int m = 1;
     int ret = addOne(&m);

     printf(" m = %d,ret = %d\n",m,ret) ;
 
     return 0;
}
//运行结果为:m = 2,ret = 2

3.指针作为函数参数

形参---指针类型变量,用来接收实参(实参是要操作的内存空间的地址)

实参---要修改谁,就把谁传过去

注意:被调函数中一定要有*p运算

值传递:只是实参数据赋值给了形参

地址(指针)传递:传的是地址--可以实现被调修改主调

int *n;
int m = 1;
addOne(n);  //传的是指针变量n里的值,是地址,但是此时n为野指针,指向是随机的
addOne(&m); //传的是m的地址

int *n = &m;//此时n为m的地址

printf("%d\n",*n);

二、指针进阶

1.指针+一维整形数组

int  a[5]; //一维整形数组

              // 数组名的类型是数据类型int[5],数组名的值是数组首元素的地址是常量,故不能做自                   增运算

(1)定义一个什么类型的指针变量

int *p = a;

int *p = &a[0];

(2)谁能代表数组所在空间的首地址

数组名---数组首元素的地址

这个地址值的类型

a<=>&a[0]  // a[0]的数据类型为int型

                 //&a[0]地址的类型为int *

=> int *p = a;   //表示p指向数组a

*p  <=> a[0]

指针的运算:

&

*

p+1

p-1

p++

p--

指针比较 > >= <= !=

p-q 表示差了多少元素(基类型),必须是同一类型的指针

p+q 不行,没有含义

int a = 10;
int *p = &a;
printf("*p = %p\n",&*p); //运行结果:*p = 0x7ffd14ae25cc
printf("*p = %p\n",*&p); //运行结果:
printf("*p = %p\n",*&a); //运行结果:
printf("*p = %p\n",&*a); //运行结果:

int a[5] = {2,5,6,8,9};
int *p = a;

printf("p = %p\n",p);
p++;
printf("p = %p\n",p);
printf("a = %p\n",a);
printf("&a[0] = %p\n",&a[0]);
printf("p + 1 = %p\n",p+1);//加n表示跳过了n个基类型
#include<stdio.h>
int main(void)
{
int a[5] = {2,5,6,8,9};
int *p = a;
int i = 0;
for (i = 0;i<5;i++)
{
    printf("a[%d] = %d\n",i,*(p+i));
    //printf("a[%d] = %d\n",i,*(a+i));//a为首地址a[0]
     printf("a[%d] = %d\n",i,a[i]);
     printf("a[%d] = %d\n",i,i[a]);
     printf("a[%d] = %d\n",i,*a++);//a为常量不能作自增
     printf("a[%d] = %d\n",i,*p++);
    //以上情况运行结果都是一样的
}
return 0;
}

*(p+i)<=>a[i]<=>*(a+i)

i[a]<=>*(i+a)

数组作为函数的参数

形参---数组形式//本质上是一个指针类型的变量:int *a

           数组长度:int len

实参---数组名  数组名代表首地址

  #include <stdio.h>                                               
  
  void getMaxArray(int *a,int len)
  {
      int i;
      int max = *a;
      for (i = 1; i < len ;i++)
      {
          if(max < *(a+i))
              max = *(a+i);
      }
      printf("max = %d\n",max);
  }
  
  void printArrayP(int *begin,int *end)
  {
      while (begin<=end)
      {
         printf("%d",*begin++);
      }
      putchar('\n');
  }
 void swap(int *a,int *b)                                                                
  {
      int t = *a;
      *a = *b;
      *b = t;
  }
  void reverseArray(int *begin,int *end)
  {
      while(begin<end)
      {
          swap(begin,end);
          begin++;
          end--;
      }
  }
  int main(void)
  {
      int a[] = {1,2,3,4,5,6,7,8,9,10};
      int len = sizeof(a)/sizeof(a[0]);
  
      reverseArray(a,a+len-1);
      printArrayP(a,a+len-1);
      printArrayP(a+3,a+8);
      getMaxArray(a,len);
 

 
      return 0;
  }


2.指针+一维字符型数组

 char s[] = "hello";

char *p = s;//推导过程和一维整形数组相同

#include <stdio.h>
{
    char s[] = "hello";
    char *p = s;

    while (*(p+i) != '\0')
    {
        putchar(*(p+i));
        ++i;
    }
  
    while (*p != '\0')
    {
       putchar(*p);
       p++;
    }
    return 0;
}

int puts(const char *s);

形参设计 const char*,其目的是为防止函数中的误操作,对应的实参可以为数组名、指针变量或直接一个字符串常量。

优点:

(1)可以提前发现问题,将运行时的问题,提前的编译时

(2)const char*可以接收char* 也可以接收 const char*,提高参数的适应性

注意:能写成const的都写成const

const  //只读

const  int a; //a此时是一个只读的变量

const int*p= &a;  //const 限定是基类型,表示不能通过*p的方式修改基类型

int const *p = &a;//与const int *p = &a等价

int * const p = &a;//const限定指针变量,表示将p限定为只读,表示p不能被修改

const int *p const p = &a;//基类型和指针变量都被限定为只读,均不能被修改,即p=&b和*p=b都是错误的

原则:就近原则 ,const离谁近就限定谁

应用:(1)如果不想通过*p方式改变基类型对应的数据,则int const *p = &a;或const int*p= &a;

(2)如果指针变量p定义好后,不想再指向别的变量,则int * const p = &a;

int a=10;
const  int *p = &a;//*p为只读。a可读可写
int * const p = &a;


a = 20;//编译结果:a = 20  *p = 20

printf("a=%d\n",a);
printf("*p = %d\n",*p);

指针 +字符串

字符串:在C语言中是按照字符数组的形式存储

处理字符串:

char s[] = "hello";//表示在栈上开辟一块空间,用字符串常量中的"hello"进行初始化

const char *p = "hello";//表示p指向了字符串常量区中的"hello",只能做读取操作,不能被修改

char s [] = "hello" //字符串常量区的数据初始化了栈上的空间,
                    //相当于将字符串常量区的hello拷贝到了栈中,
                    //可以进行修改

const char *p = "hello"; //p指向字符串常量区的hello的地址,在更改*p时会报错

void Puts(const char *s)

{

    while (*s != '\0')

  {

          putchar((*s)++);

   }

}//编译之后会报错

三、指针高阶

1.指针+二维整型数组

(1)二维数组

C语言中不存在真正的二维数组,二维数组本质是一维数组的一维数组,二维数组也符合数组的特点(连续性、有序性、单一性)

(2)从二维数组的本质出发,二维数组可写成int[3] a[2];

&a[0]

//a[0]---int [3]

//&a[0]---int [3] *

//c语言中不支持int [3] *

//正确写法int(*)[3]--数组类型的指针---数组指针

int (*p)[3] = a;//p指向二维数组a

*p<=>a[0]//相当于是内部这个一维数组的数组名,逐层访问*(p+i)<=>int[3]*(*(p+i)+j)<=>a[i][j]最终访问到具体的元素

注意:

二维数组的操作从二维数组的本质进行的,二维数组的本质一维数组的一维数组,直接的访问操作,也是一维一维的展开

2.指针+二维字符型数组

char s[][10] = {"hello","world","china"};

char(*p)[10] = s;//p指向二维数组s

*(*(p+i)+j)//操作到具体的字符

3.指针的数组

char s[10 ]= "hello"//在栈中存放字符串数据

char *p = "hello"//存放在字符串常量区中,p的类型char *,char * 的指针变量p相当于代表一个字符串

char * pstr[3] = {"hello","world","hello"};数组中存放的是各个字符串的地址

指针数组:存放地址数据的数组即指针的数组

char **q = pstr; //二级指针

char *p[] = {s[0],s[1],s[2]};//p所指向的是每个字符串的地址而不是单个的字符

char* maxOfStr(char * *p,int len)//char**p为指向字符指针数组的指针p
{
	//char max[10];

	char *max = *p;//声明一个字符指针 max 并初始化为指向数组的第一个字符串

	int i = 0;
	for (i = 1; i < len; ++i)
	{
		if (strcmp(max,*(p+i)) < 0)//max为第一个字符串
		{
			max = *(p+i);
		}
	}

	return max;
}
void reverseStr(char **begin, char **end)
{
	while (begin < end)
	{
		char *t = *begin;
		*begin = *end;
		*end = t;

		begin++;
		end--;
	}
}

void bubbleSort(char **p,int len)
{
	int i = 0;
	int j = 0;

	for (i = len-1; i > 0; --i)
	{
		for (j = 0; j < i; ++j)
		{
			if (strcmp(*(p+j),*(p+j+1)) > 0)
			{
				char *t = *(p+j);
				*(p+j) = *(p+j+1);
				*(p+j+1) = t ;//t为字符串
			}
		}
	}
}
int main(void)
{
	const char *p[] = {"hello","world","china"};  
    bubbleSort(p,3);
	puts("---------------");
	printStr(p,3);
	return 0;
}
 #include <stdio.h>
 //argc 命令行参数的个数
 //argv 存放命令行参数的字符串的指针数组
 int main(int argc, const char *argv[])                                  
 {
     printf("argc = %d\n",argc);
 
     int i = 0;
     for (i = 0; i < argc;++i)
         printf("argv[%d] = %s\n",i,argv[i]);

     return 0;
 }                                                                           
              

4.指针+函数

通过指针的方式来调用函数

函数名---代表函数入口地址

int add(int a,int b)

该函数的函数名对应的数据类为int (int a,int b)----函数类型,代表一类函数,返回值为int,带有两个int型的形参变量

int (*p) (int,int) = add;//int(int,int) *p

说明:(1)可以定义一个函数类型的指针变量,来保存函数的入口地址

(2)有了这个指针变量,通过指针变量,进行函数调用

回调函数 callback---c语言中使用了函数指针实现


int func1(int n)
{
	return n;
}

int func2(int n)
{
	return n*n;
}
int func3(int n)
{
	return n*n*n;
}


void choieSortN(int *a,int len,int(*p)(int))
{
	int i = 0;
	int j = 0;

	for (i = 0; i < len-1; ++i)
	{
		for (j = i+1; j < len; ++j)
		{
			if (p(a[i]) > p(a[j])) //函数调用 
			{
				int t = a[i];
				a[i] = a[j];
				a[j] = t;
			}
		}
	}
}


void printArray(int *a,int len)
{
	int i = 0;

	for (i = 0; i < len; ++i)
	{
		printf("%d ",a[i]);
	}
	putchar('\n');
}
int main(void)
{


	int a[] = {1,8,-3,6,5,-4,2,7};

	int len = sizeof(a)/sizeof(a[0]);

	choieSortN(a,len,func2);

	printArray(a,len);

	return 0;
}

5.指针+指针

  • 17
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值