C语言指针初步完学的学习分享

C语言指针核心概念解析

前言

这是我自己的学习指针后做的笔记,提供给大家看看,有什么错可以在评论区和我说呀比较基础,感谢大家提点

内存和地址

每一的数据在电脑内会存放在内存里

变量在不同的系统中的大小也不同

32位编译器: char: 1 字节    char*: 4 字节   short int: 2 字节

                       int: 4 字节        float: 4 字节    double: 8 字节

                       long: 4 字节     long long: 8 字节

64位编译器: char: 1 字节   char*: 8 字节   short int: 2 字节

                       int: 4 字节      float: 4 字节    double: 8 字节

                       long: 8 字节   long long: 8 字节

而要找到这个内存就要给他表一个序号,地址就是内存的序号,可以通过地址来找到相应的内存

指针变量

指针是一个变量,用来存放地址

整型指针  int* p

字符串指针  char* p

数组指针  int* p[]    char* p[]

函数指针  int(*p)(type,type)   (type是传参的类型)

结构体指针  struct name *p  (name为结构体的命名)

无类型指针/无返回值指针  void* p

void *p;  // 可以指向任何类型的数据
int a = 10;
char c = 'A';
p = &a;   // 指向int
p = &c;   // 指向char

printf("%d", *(int*)p);// 使用时需要类型转换

设置指针

*(解引⽤操作符)

#include <stdio.h>
int main()
{
  int a = 10;
  int * pa = &a;//(整型指针,&为取地址符号,取出a变量的地址)
  printf("%d",a);//打印10
  printf("%d",*pa);//打印也10
  *pa=100//改变a值为100
  printf("%d",*pa);// 再打印为100,
  return 0;
}

字符串指针

char *str = "Hello";  // 字符串常量,不可修改
char arr[] = "Hello"; // 字符数组,可以修改

// str[0] = 'h';  // 错误!字符串常量不可修改
arr[0] = 'h';     // 正确

指针运算

指针加减一个整数时,指针增加的大小与他是什么指针类型有关

设int类型指针  int* p=0X00001,p+1就是再加4( p+1=0X00001+sizeof(int))

变为0X00005(地址一般用16进制表示)

#include <stdio.h>

int main()
{
  int arr[10] = {1,2,3,4,5,6,7,8,9,10};
  int *p = &arr[0];
  int i = 0;
  int sz = sizeof(arr)/sizeof(arr[0]);//计算arr数组内有多大少元素
  for(i=0; i<sz; i++)
  {
    printf("%d ", *(p+i));
  }
  return 0;
}

const 修饰指针

const修饰的变量不可以直接改变,如下

int main()
{
	const int a = 10;
	int* pa = &a;
	printf("%d\n",a);
	//a = 100;//编译器报错,报:表达式必须是可修改的左值
	*pa = 100;//用地址找到a并且改变不会报错
	printf("%d\n", a);
	return 0;
}

const修饰的指针变量:

int const * p;//const 放在*的左边做修饰p这个指针指向的变量
int * const p;//const 放在*的右边做修饰p这个指针

野指针

1.未初始化指针而使用   -->初始化指针  int*p=NULL

(NULL表示指针或值不指向任何有效的内存位置或对象)

2.指针越界访问别的内存  -->  防止越界访问

3.指针释放未给值  -->释放后给值NULL,并在再次使用时用assert断言变量是否为NULL

数组指针

int arr[]={1,2,3,4,5};
int* p=arr;
int(*pa)[5]=&arr;//&arr是int(*)[5]的整型数组指针,所以用整型数组指针来接收,使pa指向arr数组

printf("p = %p\n", p);      // 指向第一个元素的地址
printf("p+1 = %p\n", p+1);  // 指向第二个元素,地址+4字节

printf("pa = %p\n", pa);    // 指向整个数组的地址
printf("pa+1 = %p\n", pa+1); // 指向下一个数组,地址+20字节

数组名就时数组首元素的地址(在sizeof()内单独存在时表示整一个数组)

arr[0]其实等价于*(p+0),而&arr表示整个数组的地址

使用数组指针访问数组:

#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3 };
	int* pa = arr;
	size_t sz = sizeof(arr) / sizeof(arr[0]);
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", *(pa + i));
	}
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", pa[i]);
	}
	return 0;
}

一维数组的传参本质:

一维数组传参时实参传的是数组首元素的地址,所以形参可以用相应的指针接受

type (*p),(type是指针的类型,a为每行数组的元素个数)来接收

最好把数组的元素个数一起传过来,防止指针越界访问,变成野指针

二维数组的传参本质:

二维数组在传参时是将二维数组的第一行的数组地址穿出

用 type(*pa)[a] 来接收

二级指针

指针也是变量,也有地址,指向指针地址的指针就是二级指针

int arr[]={0};
int* p=arr;
int* pa=&p;

指针数组:

数组指针是指针---- int (*p)[]=a

而指针数组是数组---- int* p[]={&a}  , 该数组内存放的是相应类型的地址

用指针数组实现二维数组:

int arr1[] = {1,2,3,4,5};
int arr2[] = {2,3,4,5,6};
int arr3[] = {3,4,5,6,7};
int* pa[3]={arr1,arr2,arr3};
int i = 0;
int j = 0;
for(i=0; i<3; i++)
{
  for(j=0; j<5; j++)
  {
    printf("%d ", pa[i][j]);//打印出相应的数
  }
  printf("\n");
}

pa[1][2]理解---->  *(*(pa+1)+2 )

(pa+1)指向pa数组的第二个元素arr2

*(pa+1)得到arr2,即arr2数组首元素的地址,

*(pa+1)+2指向arr2的第三个数组

即*(*(pa+1)+2 )为arr2的第三个元素--- 4

函数指针数组

函数指针数组是一个存放函数指针的数组,本质是数组

用于转移表,如下,将每一种计算方法放在一个数组内进行调用

#include <stdio.h>
#include <windows.h>


void menu()
{
	printf("************************\n");
	printf("*****  1.+  2.-  *******\n");
	printf("*****  3.*  4./  *******\n");
	printf("*****   0.exit   *******\n");
	printf("************************\n");

}
int Add(int x, int y)
{
	return x + y;
}
int Sud(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}

int main()
{
	int i = 0;
	int (*pf[5])(int, int) = { NULL,Add,Sud,Mul,Div};
	int x, y;
	do 
	{
		menu();
		printf("请选择:");
		scanf("%d", &i);
		if (i >= 1 && i <= 4)
		{
			printf("请输入两个参数:");
			scanf("%d%d", &x, &y);
			int r = pf[i](x, y);
			system("cls");
			printf("r = %d\n", r);
		}
		else if (i == 0)
			printf("退出\n");
		else
		{
			system("cls");
			printf("输入错误,请重新输入\n");
		}
			

	} while (i);
	return 0;
}

回调函数

将函数a穿个函数b,函数b用函数指针接收并在函数b中调用函数a

运用回调函数的冒泡排序

#include <stdio.h>
void Intexchange(int* x, int* y)
{
	int a = *x;
	*x = *y;
	*y = a;
}


void Exchange(int* p, void(*p)(int*,int*),int sz)
{
	int i, j;
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - i - 1; j++)
		{
			if (p[j] > p[j + 1])
				q(p+j, p+j+1);
		}
	}
}

void Print(int* p, int i)
{
	int j;
	for (j = 0;j < i; j++)
	{
		printf("%d ", p[j]);
	}
}

int main()
{
	int arr[] = { 9,8,7,6,5,4 };
	size_t sz = sizeof(arr) / sizeof(arr[0]);
	Print(arr, sz);
	printf("\n");//打印 9 8 7 6 5 4
	Exchange(arr, Intexchange,sz);
	Print(arr, sz);//打印 4 5 6 7 8 9
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值