iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言学习之指针知识总结
  • 554
分享到

C语言学习之指针知识总结

2024-04-02 19:04:59 554人浏览 独家记忆
摘要

目录一、地址二、指针与指针变量三、指针的作用四、初学指针时常见的错误五、通过调用函数修改主调函数中的值六、指针与一维数组七、使用函数操作一维数组八、指针变量所占字节数九、静态数组的缺

一、地址

内存中的最小单元是字节,一个字节对应一个编号,这里的编号就是对应字节的地址。换句话说,地址就是内存单元的编号。

二、指针与指针变量

指针与指针变量是两个不同的概念,指针是某个普通变量的地址,所以可以理解为,指针就是地址,地址就是指针。指针变量是一种变量,它的作用是存储其它变量的地址。

#include <stdio.h>

int main()
{
	int * p; // int *是指针类型,p是对应的变量,定义的指针变量p只能用来存储int类型变量的地址
	int i = 3, j;
	
	p = &i; // 指针变量只能用来存储对应类型变量的地址,所以这里需要对变量i进行取地址操作,即&i
	
	
	printf("%d %d\n", *p, i);
	

	j = *p; // *p就是i,所以相当于将i的值赋给了j
	printf("i = %d, j = %d\n", i, j); // 输出结果为i = 3, j = 3

	return 0;
}

三、指针的作用

指针是C语言的灵魂

  • 通过指针可以表示一些复杂的数据结构,例如,链表、树、图等
  • 通过指针可以提高传输效率
  • 利用指针可以在被调函数中修改主调函数中的多个值
  • 利用指针可以直接访问硬件
  • 通过指针可以更方便地处理字符串
  • 指针是理解面向对象语言中引用的基础

四、初学指针时常见的错误

错误1:指针变量无明确指向

#include <stdio.h>

int main()
{
	int * p;
	int i = 5;
	
	*p = i; // 出错行
	printf("%d\n", *p);

	return 0;
}

错误原因:由于p未初始化,所以p的内容是垃圾值。*p是以p的内容为地址的变量,即以一个垃圾值为地址的变量,该变量是未知的,所以当把i的值赋值给p指向的未知变量时,有可能会篡改内存中其它变量的值,而这样的操作是不允许的。

错误2:赋值时变量类型不一致

#include <stdio.h>

int main()
{
	int * p;
	int * q;
	int i = 5;
	
	p = &i;
	
	*q = p; // 出错行
	printf("%d\n", *q);

	return 0;
}

错误原因:由于p是指针类型变量,而*q是int类型变量,所以不能相互复制。

五、通过调用函数修改主调函数中的值

思考1:在下述程序中,f函数中的变量i与main函数中的变量i是不是同一个变量?

f函数中的变量i与main函数中的变量i都属于局部变量,只在自己对应的函数中起作用,所以,f函数中的变量i与main函数中的变量i不是同一个变量。

#include <stdio.h>

void f(int i)
{
	i = 99;
}

int main()
{
	int i = 66
	printf("%d\n", i);
	
	f(i);
	printf("%d\n", i);

	return 0;
}

思考2:在上述程序中,能否通过调用f函数修改main函数中变量i的值?

由于f函数中的变量i与main函数中的变量i不是同一个变量,所以把实参i传递给形参i只会改变f函数中变量i的值,当f函数执行完毕后,分配给形参i的空间会被释放,故而无法改变main函数中变量i的值。换句话说,f函数中的变量i与main函数中的变量i本质上没有任何关系,所以不管怎么修改f函数中变量i的值都不会影响main函数中变量i的值。

那要如何才能通过其它函数来修改主调函数中的值?

此时,指针就派上用场了,如下述程序:

#include <stdio.h>

void f(int * p) // 通过接收地址来确定要修改的变量
{
	*p = 99; // *p就是以p变量的内容为地址的变量,也就是要通过该函数修改的变量
}

int main()
{
	int i = 66
	printf("%d\n", i); // 输出结果为66
	
	f(&i); // 由于函数f的形参是指针变量,故需将变量i的地址发送过去
	printf("%d\n", i); // 输出结果为99

	return 0;
}

上述程序可以实现在被调函数中修改主调函数中变量的值是因为通过向被调函数传递了需要修改的变量的地址,从而确定并指向了需要修改的变量,但如果不传入地址,就会导致主调函数中的变量无法与被调函数产生关联,从而无法实现目的。

活学活用:自定义一个swap函数,用该函数互换main函数中的两个变量的值

常见错误:只传入数值,不传入地址

void swap(int a, int b)
{
	int t;
	
	t = a;
	a = b;
	b = t;
}

int main()
{	
	int a = 3, b = 5;
	
	swap(a, b);
	
	printf("a = %d, b = %d\n", a, b);

	return 0;
}

出现上述错误的原因是,main函数中的变量a和b与swap函数中的形参a和b无关,导致的结果是,主函数将3和5发送给形参a和b后,swap函数只是对3和5进行了操作,而未能对main函数中的变量a和b进行操作,所以无法互换main函数中的变量a和b的值。

正确实现方法:传入地址,定位需要互换的变量

void swap(int * p, int * q)
{
	int t;
	
	t = *p;
	*p = *q;
	*q = t;
}

int main()
{	
	int a = 3, b = 5;
	
	swap(&a, &b);
	
	printf("a = %d, b = %d\n", a, b);

	return 0;
}

思考:如下方法是否可以实现互换功能?

#include <stdio.h>

void swap(int * p, int * q)
{
	int * t;

	t = p;
	p = q;
	q = t;
}

int main()
{	
	int a = 3, b = 5;
	
	swap(&a, &b);
	
	printf("a = %d, b = %d\n", a, b);

	return 0;
}

答案是不行的,上述程序将变量a和b的地址发送给了指针变量p和q,此时,变量p和q中储存的是变量a和b的地址,然而,swap函数中的操作是互换变量p和q的内容,也就是说,当swap函数执行完毕后,变量p中储存的是变量b的地址变量q中储存的是变量a的地址,言下之意,只是将变量p和q的内容互换了而已,并没有对main函数中的变量a和b进行操作,所以无法实现互换功能,此外,几乎所有的编程语言都无法通过互换两个变量的地址实现互换变量中的值。

六、指针与一维数组

一维数组的数组名

一维数组的数组名是一个指针常量,该常量是一维数组中第一个元素的地址。

#include <stdio.h>

int main()
{
	int a[5];
	int b[5];
	
	a = b; // 错误,因为a和b都是常量,所以无法进行赋值操作
	a = &a[2]; // 错误,因为a是常量,无法对一个常量进行赋值操作
	
	return 0;
}
#include <stdio.h>

int main()
{
	int a[5];

	printf("%#X", &a[0]);
	printf("%#X", a); // 与上一行输出结果相同,因为一维数组名就是数一维组中第一个元素的地址

	return 0;
}

引用一维数组中的元素

通过下标引用:如a[i]表示第i+1个元素

通过指针引用:如*(a+i)表示第i+1个元素

#include <stdio.h>

int main()
{
	int a[5];
	int i;
	
	for (i = 0; i < 5; i++) // 向一维数组中读入元素
		scanf("%d", &a[i]); // 通过下标引用数组中的元素

	for (i = 0; i < 5; i++) // 输出一维数组的内容
		printf("%d ", *(a + i)); // 通过指针引用数组中的元素

	return 0;
}

指针变量的运算

指针变量不能相加,相乘以及相除,只能进行相减。如果两个指针变量指向同一块连续空间的不同存储单元,则这两个指针变量才可以进行相减运算。两个指针变量相减得到的结果是两个指针变量间相隔的元素个数。

#include <stdio.h>

int main()
{
	int a[5];
	int * p = &a[1];
	int * q = &a[4];

	printf("%d\n", q - p); // 输出结果为3,证明相隔3个元素

	return 0;
}

七、使用函数操作一维数组

使用函数对一维数组进行操作,首先要将数组名传递给函数,因为一维数组名是函数第一个元素的地址,传递数组名就相当于传递起始位置,其次,普通数组不同于字符数组,它们没有结束的标志,所以还需要向函数传递数组长度以确定数组何时结束。故想要在另外一个函数中对一维数组进行操作需要向该函数传入两个参数,数组名和数组长度。

定义函数时的形参有两种写法,第一种是(int a[], int length),第二种是(int * a, int length)。可以写第二种的原因是一位数组名本身就是指针常量,所以可以直接用指针变量来接收。

定义一个函数,该函数的功能是对一维数组的内容进行输出

#include <stdio.h>

// 自定义的print函数,其功能是将一维数组输出
void print(int a[], int length)
{
	int i;

	for (i = 0; i < length; i++)
		printf("%d ", a[i]); // 也可以写成printf("%d ", *(a+i));
	
	printf("\n");
}

int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int b[6] = { -1, -2, -3, -4, -5, -6 };
	int c[100] = { 23, 88, 99, 44 };

	print(a, 5);
	print(b, 6);
	print(c, 100);

	return 0;
}

八、指针变量所占字节数

预备知识:sizeof运算符的用法

sizeof(数据类型):其值为对应数据类型所占的字节数

例如:sizeof(int)值为4;sizeof(double)值为8;sizeof(char)值为1

sizeof(变量):其值为对应变量所占的字节数

#include <stdio.h>

int main()
{
	char c = 'A';
	int i = 99;
	double x = 66.66;

	char * p = &ch;
	int * q = &i;
	double r = &x;

	printf("%d %d %d\n", sizeof(c), sizeof(i), sizeof(x)); // 输出结果为1 4 8
	printf("%d %d %d\n", sizeof(p), sizeof(q), sizeof(r)); // 输出结果均为4

	return 0;
}

上述程序证明,尽管普通类型变量所占的空间大小不一致,但它们对应的指针变量都占四个字节。

九、静态数组的缺陷

数组长度必须事先指定,且只能是常整数,不能是变量

数组的长度在长度不能在函数执行过程中动态的增减,数组一旦定义,其长度就无法改变

程序员无法手动释放静态数组的内存,数组一旦定义,操作系统为该数组分配的存储空间就会一直存在,直到该数组所在的函数执行完毕后,该数组的空间才会被操作系统释放

在某个函数内定义的静态数组在该函数执行期间可以被其它函数使用,但当该函数执行完毕后,该函数中定义的数组就无法在其它函数中使用,这是因为该函数执行完毕后,静态数组的内存就被会被释放

十、malloc函数

malloc这个词是由memory(内存)与allocate(分配)这两个单词合成的,顾名思义,malloc函数就是用来分配内存的函数。

#include <stdio.h>
#include <malloc.h>

int main()
{
	int i; // 静态分配了4个字节的存储空间

	int* p = (int*)malloc(4);
	

	free(p); 
	

	return 0;
}

十一、动态数组的构造

#include <stdio.h>
#include <malloc.h>

int main()
{
	int a[10]; // 静态构造一维数组
	int length;
	int* pArray;
	int i;
	
	scanf("%d", &length);

	pArray = (int*)malloc(sizeof(int) * length);
	

	// 对该动态一维数组手动赋值
	for (i = 0; i < length; i++)
		scanf("%d", &pArray[i]);

	// 输出该动态一维数组的内容
	for (i = 0; i < length; i++)
		printf("%d ", *(pArray + i));
	
	printf("\n");

	free(pArray); // 释放该动态数组

	return 0;
}

十二、静态内存与动态内存的对比

静态内存是由操作系统自动分配,自动释放的。静态内存是在栈中分配的;动态内存是由程序员手动分配,手动释放,但如果只分配不释放就会导致内存泄露,也就是内存越用越少。动态内存是在堆中分配的。

十三、多级指针

#include <stdio.h>

int main()
{
	int i = 10;
	int * p = &i;
	int ** q = &p;
	int *** r = &q;
	
	r = &p; // 错误,因为r是int *** 类型,它只能用来存储int ** 类型变量的地址
	
	printf("i = %d\n", ***r);

	return 0;
}

表解上述程序:

变量名变量地址变量内容
i1000H10
p2000H1000H
q3000H2000H
r4000H3000h
变量名对应变量
*rq
**rp
***ri
#include <stdio.h>

void g(int ** q) // 由于p的类型是int *,所以q的类型必须是int **,因为q要用来存放p的地址
{
	
}

void f()
{
	int i;
	int * p;
	
	p = &i;
	
	g(&p); // 要通过g函数修改p的内容,则必须发送p变量的地址
}

int main()
{
	f();

	return 0;
}

十四、跨函数使用内存

由于静态内存是在栈中分配的,而函数执行完毕后,栈中的静态内存就会全部出栈,而动态内存是在堆中分配的,当函数执行完毕后,堆中分配的内存并不会像栈中分配的内存一样直接被释放掉,所以

静态内存是不能跨函数使用的,而动态内存是可以的。

思考:下述程序是否有语法错误?是否有逻辑错误?

#include <stdio.h>

void f(int** q)
{
	int i = 5;

	*q = &i; // 由于q储存了p的地址,所以*q就是p,这行代码实质是将i的地址赋给了p
}

int main()
{
	int* p;

	f(&p);

	printf("i = %d\n", *p); // 由于p储存了i的地址,所以*p就是i

	return 0;
}

上述程序没有语法错误,但是有逻辑上的错误,这是因为,当f函数执行完毕后,f函数中所有的静态变量的内存都会被释放掉,所以当执行到printf("i = %d\n", *p);时,p所指向的变量空间的访问权限已经返还给了操作系统,这样就会导致*p访问了不属于该程序的空间。这个程序说明了在一个函数内部定义的静态变量在该函数中执行完毕后就不再可以垮函数使用。

思考:对比上一程序,下述程序是否有语法错误?是否有逻辑错误?

#include <stdio.h>

void f(int** q)
{
	*q = (int*)malloc(sizeof(int));
	
	**q = 5;
}

int main()
{
	int* p;

	f(&p);

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

	return 0;
}

上述程序是完全没有语法错误的,因为当f函数执行完毕后,其中分配的动态内存不会自动释放,所以在main函数中依然可以使用这段内存。这个程序体现出,在一个函数中分配的动态存储空间在该函数执行完之后,仍然可以在另外一个函数中使用。

趁热打铁:下列四个程序中,哪个程序能够通过调用fun函数使main函数中的指针变量p指向一个合法的整型单元?

#include <stdio.h>

void fun(int * p)
{
	int s;
	p = &s;
}

int main()
{
	int * p;

	fun(p);

	return 0;
}
#include <stdio.h>

void fun(int ** p)
{
	int s;
	*p = &s;
}

int main()
{
	int * p;

	fun(&p);

	return 0;
}
#include <stdio.h>
#include <malloc.h>

void fun(int * p)
{
	p = (int *)malloc(sizeof(int));
}

int main()
{
	int * p;

	fun(p);

	return 0;
}
#include <stdio.h>
#include <malloc.h>

void fun(int ** p)
{
	*p = (int *)malloc(4);
}

int main()
{
	int * p;

	fun(&p);

	return 0;
}

以上就是C语言学习之指针知识总结的详细内容,更多关于C语言指针的资料请关注编程网其它相关文章!

--结束END--

本文标题: C语言学习之指针知识总结

本文链接: https://www.lsjlt.com/news/153870.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C语言学习之指针知识总结
    目录一、地址二、指针与指针变量三、指针的作用四、初学指针时常见的错误五、通过调用函数修改主调函数中的值六、指针与一维数组七、使用函数操作一维数组八、指针变量所占字节数九、静态数组的缺...
    99+
    2022-11-13
  • C语言学习之函数知识总结
    目录前言一、引入二、认识函数三、函数的作用四、函数的返回值五、定义函数六、函数的类型七、return语句与break语句的区别八、函数的分类九、主函数十、函数使用举例十一、函数的声明...
    99+
    2022-11-13
  • C语言进阶学习之指针
    目录1.指针概念回顾2.字符指针3.数组指针和指针数组3.1数组指针的含义3.2&数组名vs数组名3.3数组指针4.数组传参和指针传参4.1一维数组传参4.2二维数组传参4....
    99+
    2022-11-12
  • C语言之初识指针
    指针是什么? 那到底什么是指针呢,其实指针和之前学习的变量基本相似,不过变量里面放的是一些值,而指针里面放的是它所指的地方的地址。在声明一个变量是,计算机就会为该变量预留一个位置,而...
    99+
    2022-11-12
  • 详解C语言学习记录之指针
    目录1指针是什么2指针和指针类型3野指针(1)三种情况(2)如何规避野指针4指针运算5指针和数组6字符指针7数组指针8指针数组9其他总结1指针是什么 指针是汇编语言中的一个对象,利用...
    99+
    2022-11-12
  • C语言指针用法总结
    1、先谈谈内存与地址 引例: 计算机的内存看成大街上的一排房屋,每个房屋都要有门牌号,这个就相当于计算机的内存地址,而房屋里面住的人、家具等等就相当于需要存放的各种各样的数据,所以要...
    99+
    2022-11-12
  • C语言指针之必须要掌握的指针基础知识
    目录一、指针概述指针的创建指针的大小如何使用指针二级指针二、野指针形成野指针的原因如何规避野指针三、指针的基本运算指针± 整数指针-指针四、指针和数组五、指针数组总结一、指针概述 指...
    99+
    2022-11-12
  • 从头学习C语言之指针和数组
    目录指针和数组:示例:总结指针和数组: 数组名其实是数组第一个元素的地址。 %p用来打印地址,为十六进制 &:取址操作符 如果用一个指针指向数组,应该怎么做呢? char ...
    99+
    2022-11-13
  • C语言学习之指针的使用详解
    目录一、指针概念1.指针变量2.指针类型3.二级指针二、野指针1.野指针成因2.规避野指针三、指针运算1.指针±整数2.指针-指针3.指针关系运算四、指针数组1.指针和...
    99+
    2022-11-13
    C语言指针使用 C语言指针
  • Spring5学习之基础知识总结
    目录1.概述2.入门Demo3.源码1.概述 1、Spring 是轻量级的开源的 JavaEE 框架 2、 Spring 可以解决企业应用开发的复杂性 3、Spring 有两个核心部...
    99+
    2022-11-12
  • C语言基础知识点指针的使用
    目录一、指针的作用二、地址与指针三、指针变量四、数组与指针五、指针自加自减运算六、指向指针的指针七、指针变量作为函数形参八、函数指针九、函数指针数组十、指针的应用场景一、指针的作用 ...
    99+
    2022-11-13
  • C语言小知识之为什么要使用指针详析
    刚开始学习C语言的时候,感觉最难理解的就是指针,什么指针变量,变量指针,指向指针的变量,指向变量的指针?一堆概念,搞得人云里雾里的,今天不讨论这些概念的问题,从最底层来分析C语言中为...
    99+
    2022-11-12
  • Go语言基础学习之指针详解
    目录1. 什么是指针2. 指针地址 & 指针类型3. 指针取值4. 空指针5. make6. new7. make 和 new 的区别8. 问题今天来说说 Go 语言基础中的...
    99+
    2022-12-30
    Go语言指针使用 Go语言指针 Go 指针
  • C语言学习基础知识分享
    目录写在前面为何学习C语言语言层面个人层面初识C语言什么是语言标准hellowordmainprintf数据类型byte & bitsizeof常量常量分类变量定义变量变量的...
    99+
    2023-01-28
    c语言入门自学零基础 c语言入门教程 c语言入门基础知识
  • Java基础学习之字符串知识总结
    目录一、前言二、String 类(字符串常量)2.1 String 类实例的创建2.2 String 对象的比较2.3 String对象的空值2.4 字符串拼接三、StringBui...
    99+
    2022-11-12
  • C语言指针的相关知识点有哪些
    这篇文章将为大家详细讲解有关C语言指针的相关知识点有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。第一站 字符指针----存放字符地址的指针1.使用方法(1)直接使用字符int main()...
    99+
    2023-06-29
  • Go语言学习之指针的用法详解
    目录引言一、定义结构体1. 语法格式2. 示例二、访问结构体成员三、结构体作为函数参数四、结构体指针总结引言 Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义...
    99+
    2022-11-13
  • Python入门学习之类的相关知识总结
    目录前言一、类的定义和使用二、类的方法三、类的属性四、类中常用特殊方法前言 Python是面向对象的程序设计(Object Oriented Programming)。 面向对象的程...
    99+
    2022-11-12
  • python基础学习之递归函数知识总结
    目录一、递归函数使用注意点二、递归的效率问题三、递归函数引入四、递归的深度五、通过缓存解决递归限制六、递归函数使用示例一、递归函数使用注意点 递归函数一定要编写终止条件,否则将产生无...
    99+
    2022-11-12
  • c语言中指针零基础知识点有哪些
    小编给大家分享一下c语言中指针零基础知识点有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1.指针是什么(可能有点难理解)指针的是啥?指针实际上就是地址,地址...
    99+
    2023-06-29
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作