ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

C指针细节

2022-08-01 19:32:20  阅读:112  来源: 互联网

标签:变量 int 地址 细节 内存 printf 指针


C指针细节

悬空指针
C语言中的指针可以指向一块内存,如果这块内存稍后被操作系统回收(被释放),但是指针仍然指向这块内存,那么,此时该指针就是“悬空指针”。
例子:

void *p = malloc(size);
assert(p);
free(p); //现在p就是一个悬空指针

“悬空指针”会引发不可预知的错误,而且错误一旦发生,难以定位。这是因为在 free(p) 之后,p 指针仍然指向之前分配的内存,如果这块内存暂时可以被程序访问并且不会造成冲突,那么之后使用 p 并不会引发错误。
在实际开发中,为了避免出现”悬空指针“,在释放内存之后,常常会将指针 p 赋值为 NULL:

void *p = malloc(size);
assert(p);
free(p); 
// 避免“悬空指针”
p = NULL;

这么做的好处是一旦再次使用被释放的指针 p,就会立刻引发“段错误”,方便查找错误点。
段错误是计算机软件运行过程中可能出现的一种特殊错误情况。当程序试图访问不允许访问的内存位置,或试图以不允许的方式访问内存位置(例如尝试写入只读位置,或覆盖部分操作系统)时会发生段错误。

野指针
“悬空指针”是指向被释放内存的指针,“野指针”则是不确定其具体指向的指针。“野指针”最常来自于未初始化的指针,例如:

void *p;
// 此时 p 是“野指针”

因为“野指针”可能指向任意内存段,因此它可能会损坏正常的数据,也有可能引发其他未知错误,所以C语言中的“野指针”危害性甚至比“悬空指针”还要严重。
在实际开发中,定义指针时,一般都要尽量避免“野指针”的出现(赋初值):

void *p = NULL;
void *data = malloc(size);

C语言运算符

内存地址的概念

多级指针案例 取出子函数中临时变量的地址

指针变量的赋值只能赋予地址, 决不能赋予任何其它数据。在C语言中, 变量的地址是由编译系统分配的,C语言中提供了地址运算符&来表示变量的地址。一个指针变量可以认为它是在一个.c文件中是全局的。
int *p = &a;
*指针变量 的作用是获取指针变量指向的内存空间的内容
修改指针,需要用指针的指针

"*"的两种用法:

1)用于定义一个指针变量

2)存储指针变量储存的存储空间的内容

指针常见的应用场景

1)在函数中可以修改主调函数中变量的值

2)让函数可以有多个返回值

多级指针

int* p; int 类型的一级指针;
int** p2; int 类型的二级指针;

二级指针变量只能保存一级指针变量的地址;
有几个* 就是几级指针 int*** 三级指针。

通过int类型三级指针 操作int类型变量的值 ***p

#include <stdio.h>
void swap (int *p1,int *p2)
{
    int t;
    int*p;
    t=*p1;
    *p1=*p2;
    *p2=t;
//    p=p1;
//    p1=p2;
//    p2=p;
}
void swap2(int **m, int**n)
{
    int*p;
    p=*m;
    *m=*n;
    *n=p;
}
void main( )
{
	//&取地址,*取值  
    int a=1,b=2,*p=&a,*q=&b;
    printf("%d,%d,%d,%d\n",a,b,*p,*q);
    printf("%d,%d,%d,%d\n",&a,&b,&(*p),&(*q));
    swap(p,q);
    printf("%d,%d,%d,%d\n",a,b,*p,*q);
    printf("%d,%d,%d,%d\n",&a,&b,&(*p),&(*q));
    swap2(&p,&q);
    printf("%d,%d,%d,%d\n",a,b,*p,*q);
    printf("%d,%d,%d,%d\n",&a,&b,&(*p),&(*q));
 
// ,
//1,2,1,2
//	6422300,6422296,6422300,6422296
//	2,1,2,1
//	6422300,6422296,6422300,6422296
//	2,1,1,2                     
//	6422300,6422296,6422296,6422300

}

int main(){
	int number  = 5;
	int *ptr = &number;
	
	printf("number's address = [%p]\n",&number);//number的地址
	printf("number's value = [%d]\n",number);//number的值
	printf("ptr's address:%p\n",&ptr);//(指针变量)ptr的地址
	printf("ptr's value:%p\n",ptr);//ptr的值
	printf("ptr pointing value:%d\n",*ptr);//ptr指向的变量的值
	/*
	number's address = [0061FF1C]
	number's value = [5]
	ptr's address:0061FF18
	ptr's value:0061FF1C
	ptr pointing value:5	
	*/
	return 0;
}

#include<stdio.h>
#include<stdlib.h>
/**
main函数获取子函数中临时变量的地址
这其实还是值传递和引用传递的问题
*/
function(int** pointer) {
	int i = 123;
	*pointer = &i;
	printf("i的地址%#x\n", &i);
}

main() {
	int* pointer1;
	function(&pointer1);
	printf("pointer1的值%#x\n", pointer1);
	system("pause");
}

i的地址0x1147410c
pointer1的值0x1147410c

联合体(共用体)

长度(大小)等于联合体中定义的变量当中最长的那个,联合体只能保存一个变量的值
联合体共用同一块内存,在嵌入式设备中起到节省内存的目的.
共用体也是用户自定义的数据类型,不过该类想中的所有成员共用一块内存,因此一个成员变量赋值,就等于所有成员都被赋予了相同的值。

    #include<stdio.h>
    #include<string.h>
    union book
    {
    	char name[10];
    	char price[10];
    };//定义一个共用体,有2个成员,name和price,这2个成员共用一块内存,因此他们的地址相同
    int main()
   {
    	union book mybook;
    	strcpy(mybook.name,"呼啸山庄");
    	strcpy(mybook.price,"11元8角");
    	printf("name的地址 :%p\n",&mybook.name);
    	printf("price的地址:%p\n",&mybook.price);//输出结果显示它们的地址相同
    	printf("书名:%s\t",mybook.name);
    	printf("价格:%s\n",mybook.price);//由于price1被赋值时,覆盖了name1成员的值,因此他们的值也是一样的
    	return 0;
   }
    
//name的地址 :0x7ffde4ac2a46
//price的地址:0x7ffde4ac2a46
//书名:11元8角 价格:11元8角

typedef void (*Fun) (void) 的理解——函数指针——typedef函数指针

//返回类型(*函数名)(参数表) 
//定义一个函数指针pFUN,它指向一个返回类型为char,有一个整型的参数的函数
char (*pFun)(int);

//定义一个返回类型为char,参数为int的函数
//从指针层面上理解该函数,即函数的函数名实际上是一个指针,
//该指针指向函数在内存中的首地址
char glFun(int a)
{
    cout << a;
    //return a;
}

int main()
{
//将函数glFun的地址赋值给变量pFun
    pFun = glFun;
//*pFun显然是取pFun所指向地址的内容,当然也就是取出了函数glFun()的内容,然后给定参数为2。
    (*pFun)(2);
    return 0;
}

typedef函数指针

//typedef  返回类型(*新类型)(参数表)
typedef char (*PTRFUN)(int); 
PTRFUN pFun; 
char glFun(int a){ return;} 
void main() 
{ 
    pFun = glFun; 
    (*pFun)(2); 
} </span>

typedef的功能是定义新的类型。第一句就是定义了一种PTRFUN的类型,并定义这种类型为指向某种函数的指针,
这种函数以一个int为参数并返回char类型。后面就可以像使用int,char一样使用PTRFUN了。
第二行的代码便使用这个新类型定义了变量pFun,此时就可以像使用形式1一样使用这个变量了。

标签:变量,int,地址,细节,内存,printf,指针
来源: https://www.cnblogs.com/kato-T/p/16541581.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有