指针基础运用

1.指针的定义与引用

源360百度

指针的定义

        在计算机科学中,指针(Pointer)是编程语言中的一个对象,它利用地址,其值直接指向存在电脑存储器中另一个地方的值。因此,将地址形象化的称为指针。意思是通过它能找到以它为地址的内存单元。

指针的作用

        指针除了能够提高程序的效率,更重要的是能使一个函数访问另一个函数的局部变量,因此指针是两个函数进行数据交换必不可少的工具。程序中的数据对象总是存放在内存中,在生命期内这些对象占据一定的存储空间,有确定的存储位置。实际上,每个内存单元都有一个地址,即以字节为单位连续编码。编译器将程序中的对象名转换成机器指令能识别的地址,通过地址来存取对象值。通过对象地址存取对象的方式称为指针间接访问2指针的定义_定义指针。

指针的定义方式

        在C语言中,指针变量的定义方式是在数据类型后面加上一个星号*,然后是变量名。例如,定义一个指向整型数据的指针变量p1,可以写作int *p1;定义一个指向字符型数据的指针变量p2,可以写作char *p2。这里的int和char是指针指向的地址所存放数据的数据类型

int *pa;

上述代码中,int表明了指针所指变量类型,星号(*)表明声明的变量是一个指针,int *pa; 声明的意思是pa是一个指针,*pa的类型为int类型。

将变量地址赋给指针变量的方式

1.在定义指针变量的同时,为其赋值。

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

int main()
{
    int a = 0;
    int *pa = &a;		//&a-对变量a取地址,取出a的地址
                        //将变量a的第一个字节的地址放在pa中
    printf("%p\n", &a);
    printf("%p", pa);
    
    return 0;
}

输出结果:

注意:每次输出结果可能不同,因为内存是随机分配的。

2.先定义指针变量,再对其进行赋值。

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

int main()
{
	int *pb;
	int b = 10;
	pb = &b;
    
	printf("%p\n", pb);
	printf("%p", &b);

	return 0;
}

输出结果:

当基类行不同时我们需要强制类型转换

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

int main()
{
	int a = 10;
	double *pa;
	pa = (double*)&a;
	return 0;
}

如何通过指针对相关普通变量进行改变数值呢(即如何通过指针变量找到普通变量)?

思路:

通过指针改变普通变量的数值

在C语言中,指针是一种强大的工具,它允许我们直接操作内存地址,从而实现对普通变量的数值进行改变。以下是通过指针改变普通变量数值的基本步骤和注意事项。

创建指针并指向普通变量

首先,我们需要声明一个指针变量,并使其指向我们想要操作的普通变量。这通常通过取地址运算符&来完成。例如,如果我们有一个整型变量a,我们可以声明一个指向整型的指针p,并通过赋值操作p = &a使指针指向a

int a = 5;
int *p = &a;  // p现在指向a 

通过指针改变普通变量的值

一旦指针指向了普通变量,我们就可以通过指针来访问和修改该变量的值。这是通过解引用运算符*来实现的。例如,如果我们想要将a的值改为10,我们可以通过*p = 10来实现

*p = 10;  // a的值现在变为10 
#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

int main()
{
	int c = 0;
	int *pc = &c;
	printf("%d\n", c);
	*pc = 55;		//*-解引用操作
	printf("%d", c);

	return 0;
}

输出结果:

空指针

可理解为空指针是被预留的内存,表示指针不会只想任何对象

空指针(Null Pointer)是指一个指针变量没有被初始化,即没有被赋予具体的内存地址。在程序中,空指针表示指向空的内存地址。空指针实质上是有指向的指针,但它指向的地址是很小的地址,约定俗成为地址0。这个地址不允许存放数据,也不允许程序访问,所以空指针不能操作该地址里的东西,我们就理解为指针指向了空,无法操作了

构造空指针的两种方法:

int *pa = NULL;//NULL是宏定义,其作用等价于0
int *pb = 0;

野指针

定义:野指针就是指针指向不明确,或是随机的,没有限制的。

野指针的成因:

a.指针未初始化

int *pa;
*pa = 10;

解决方法:指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。

int *pa = NULL;

b.指针越界访问

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

int main() {
    int arr[4] = { 1,2,3,4 };
    int *pb = arr;
    int i = 0;
    /* 在此数组有四个元素,而在指针变量在数组进行访问时却访问了五个元素的大小,
  从而导致了此结果 */
    for (i = 0;i <= 4;i++) {
        printf("%d\n", *pb);
        pb++;
        }
    return 0;
}

输出结果:

解决方法:

明确指针的访问范围。

c.指针指向的空间释放了( free和 delete它们两个把指针所指的内存给释放掉,但并没有把指针本身干掉 )

2.指针类型

指针都有数据类型:

int类型指针、char类型指针、float类型指针、void类型指针......

指针变量的不同指针类型在解引用时一次性访问几个字节呢?(int类型与char类型进行比较)

int类型指针

char类型指针

二者对比之后可得指针解引用访问字节数与指针类型相关。

那么如何指针类型有什么作用呢?

解答:可以帮助我们运用不同类型的指针变量对数值元素进行访问,如 如果我们相访问可以运用short类型指针解引用调到那一项上去。

一个小题

利用函数和指针进行两数交换

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

void Swap(int* pa, int* pb) {
	int temp = *pa;
	*pa = *pb;
	*pb = temp;
}

int main() {
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	printf("交换前的值 a=%d,b=%d\n", a, b);
    
	Swap(&a,&b);
    
	printf("交换后的值 a=%d,b=%d", a, b);
	return 0;
}

3.指针相关运算

指针相关运算主要分为三类:
a.指针加减整数;

b.指针-指针;

c.指针关系运算;

a.指针加减整数(其中包含了指针的自增与自减)

p+n:指向p当前所指元素之后的第n个元素

p-n:指向p当前所指元素之前的第n个元素

p++:系统会根据p的基类型增加相应的字节个数,p指针自身数值发生变化

p++:系统会根据p的基类型减少相应的字节个数,p指针自身数值发生变化

int a=0;
int *pa=&a;
pa=pa+1;
pa++;

指针的自增自减:如p++就等价于p+1。

*p++等价于*(p++)

b.指针-指针

指针-指针 其结果是两个指针之间地址之差除以指针类型所占字节数。

注意:在进行指针-指针运算时,必须要是同类指针才行

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

int main()
{
	int* pa = 1000;
	int* pb = 1012;
	printf("pa = %d\n",  pa);
	printf("pb = %d\n",  pb);
	printf("pb-pa = %d ", pb - pa);
	return 0;
}

输出结果:

c.指针关系运算(即比较指针的大小)

前提:两指针的类型相同,否则不可进行比较

设a和b是同类型指针(结果 为 真 则返回1,结果为 假 则返回0):
a==b:判断两指针是否指向同一变量

a!=b:判断两指针是否指向不同变量

a>b:判断a指针是否在b指针之

c.指针关系运算(即比较指针的大小)

前提:两指针的类型相同,否则不可进行比较

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

int main()
{
	int* pa = 1000;
	int* pb = 1001;
	printf("%d\n", pa > pb);
	printf("%d\n", pa < pb);
	return 0;
}

输出结果:

4.指针与数组

指针与数组的关系主要分为以下几类:

a.一维数组与指针

b.二维数组与指针

c.字符串与指针

d.指针数组

为何数组与指针可以结合起来使用呢?

解答:数组是有相同类型元素组合起来的,每个数组元素不仅占用的内存单元得字节数相同而且是连续的

a.一维数组与指针

注意:数组名表示的是数组首元素的地址

那么如何将指针和数组结合起来呢?

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,10 };
	int* pa=0;
    int i=0;
	pa = arr;  //此时我们就把数组arr的首元素地址赋给了指针pa
    for(i=0;i<10;i++){
        printf("%d ",*(p+i));
    }
    
	return 0;
}

其思路就是将数组元素的地址付给指针变量

那么如何将数组中的其他元素用指针表示出来呢?

思路:可以根据每个数组元素占用的内存单元得字节数相同而且是连续的性质,结合指针的加法运算来将数组中的元素表示出来。

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

int main()
{
	int arr[10] = {0};
	int* pl =0;
	pl = arr;
	int i = 0;

	//对数组arr进行赋值
	for (i = 0; i < 10; i++) {
		*pl = i;
		pl++;
	}
    
	pl = arr;//在对arr付完值之后,将指针地址放的数组元素首地址的位置,方便后续打印

	//打印数组
	for (i = 0; i < 10; i++) {
		printf("%d ", *pl);
		pl++;
	}
    
	return 0;
}

输出结果:

b.二维数组与指针

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

int main()
{
	int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
	int (*p)[4] = arr;
	//两种访问数组元素的方法
	//方法一:我们访问第2行第2列的元素
	printf("%d\n",*(*(p+1)+1));
	//方法二:我们访问第2行第3列的元素
	printf("%d", *(p[1] + 2));
	return 0;
}

一个小题

利用指针把一个二维数组打印出来

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

void print(int (*p)[4], int x, int y) {
	int i = 0;
	int j = 0;
	for (i = 0; i < x; i++) {
		for (j = 0; j < y; j++) {
			printf(" %d  ", p[i][j]);
		}
		printf("\n");
	}
}

int main()
{
	int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
	print(arr, 3, 4);
	return 0;
}

c.字符串与指针

当我们用指针访问字符串时我们既可以数组,也可以不使用数组,接下来我们不用数组来打印字符串

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

int main()
{
	char* string = "The sun is bigger today than it was yesterday.";
	printf("%s", string);
	return 0;
}

d.指针数组

指针数组是什么呢?

解答:我们根据整形数组,可推出指针数组就是存放指针的数组。

在将解指针数组之前我们先来看一下什么是二级指针。先来看一下以下代码:

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

int main()
{
	int a = 20;
	int* pa = &a;
	printf("%d\n", pa);
	int** ppa = pa;
	printf("%d", ppa);
	return 0;
}

二级指针其实是一个指向指针的指针,在C语言中,二级指针主要用于多级数据间的传递。

*二级指针 == 一级指针本身

**二级指针 == 二级指针所指向的变量

接下来我们看一下通过指针数组引用二维数组:

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

int main()
{
	int a[4] = { 1,2,3,4 };
	int b[4] = { 5,6,7,8 };
	int* arr[2] = { a,b };
	int i = 0;
	for (i = 0;i < 2;i++) {
		int j = 0;
		for (j = 0;j < 4;j++) {
			printf("%d ",arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

一个小题

用二级指针访问字符串数组并依次打印字符串数组的元素

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

int main()
{
	char* cities[] = { "beijing","sichuan","shanghai","xiamen" };
	char** found;
	int i = 0;
	for (i = 0;i < 4;i++) {
		found = cities + i;
		printf("%s\n", *found);
	}
	return 0;
}

输出结果:

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

void Swap(int* pa, int* pb) {
	int temp = *pa;
	*pa = *pb;
	*pb = temp;
}

int main() {
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	printf("交换前的值 a=%d,b=%d\n", a, b);
    
	Swap(&a,&b);
    
	printf("交换后的值 a=%d,b=%d", a, b);
	return 0;
}

那么Swap函数从这两个参数中获得了什么呢? 他获得了该元素的地址,知道要在该位置上找出一个整数。

b.返回指针类型数据的函数(指针函数)

指针变量也可以指向一个函数,然后通过指针变量调用此函数这种函数返回指针值

和普通函数运用方法相同

#define  _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int* fun(int*, int*);
main()
{
	int* p, m, n;
	printf("Enter two number:"); 
	scanf("%d%d", &m, &n);
	p = fun(&m, &n);
	printf("m=%,n=%d,*p=%d\n", m, n, *p);
}
int* fun(int* a, int* b)
{
	if (*a > *b) return a;
	return b;
}

c.使用指针数组作为main()函数的参数

大多数时候main()函数都是没有参数的,但其实main()函数可以无参数,也可以有参数,main()函数有参数的格式如下:

main(int argc,char *argv[])

6.指针与结构体

结构体指针

一个指针变量用来指向一个结构体变量。此时该指针变量的值是结构体变量的起始地址,该指针称为结构体指针。结构体指针可访问该结构体变量、初始化结构体成员变量。

那么如何将指针和结构体结合呢?请看以下代码:

struct stu
{
	char name[10];
	char sex;
	int age;
	float score;
}s, * p;
p = &s;//p是指向结构体变量的结构体指针

如何使用指针读取结构体中的成员呢?

我们主要有以下3种方法:

a.使用运算符( . ),如 s.name,s.sex,s.age

b.使用运算符( * ),如(*p).mame

c.使用运算符( -> ),如p->name

其中使用运算符( -> )更为常见。

接下来我们用代码来体现一下这三种方法:

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

struct stu
{
	char name[10];
	char sex[10];
	int age;
	float score;
}s,*p2,*p3;

int main()
{
	struct stu s1 = { "zhangsan", "nan", 18, 97.5f };
	struct stu s2 = { "lisi","nan", 18, 95.5f };
	struct stu s3 = { "ruhua","nv",17, 99.0f };
	p2= &s2;
	p3 = &s3;
	printf(" %s , %s , %d , %.2f\n",s1.name, s1.sex, s1.age, s1.score);
	printf(" %s , %s , %d , %.2f\n",(*p2).name , (*p2).sex, (*p2).age, (*p2).score);
	printf(" %s , %s , %d , %.2f\n",p3->name, p3->sex, p3->age, p3->score);
    //当然我们也可以使用结构体数组与指针实现三位同学的信息输出
	return 0;
}

输出结果:

当然我们也可以使用结构体数组与指针实现三位同学的信息输出

#define  _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

struct stu
{
	char name[10];
	char sex[10];
	int age;
	float score;
}s[3] = {
	{ "zhangsan", "nan", 18, 97.5f },
	{ "lisi","nan", 18, 95.5f },
	{ "ruhua","nv",17, 99.0f }
},*p;

int main()
{
	p = s;
	printf(" %s , %s , %d , %.2f\n", s[0].name, s[0].sex, s[0].age, s[0].score);
	printf(" %s , %s , %d , %.2f\n", (p+1)->name,(p+1)->sex,(p+1)->age,(p+1)->score);
	return 0;
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值