jQuery鼠标指针特效

C指针细节

C语言中的*和&具体分析

在C语言中的用法
指针的声明:int *p 或 int* p; 读法:p是指向一个整数类型的指针。
复合指针: int **p;或int** p; 读法 p是一个指向一个指向整数类型的指针的指针。
解引用: x=*p 把指针p指向的值赋值给x。

int a = 10;
int *p = &a;
*p是一个int类型的指针
&p表示的是一个地址,&是取地址符(号)

printf(“%d\n”, a); 
printf(“%d\n”, &a); 
printf(“%d\n”, b); 
printf(“%d\n”, *b);

结果: 
10 
6487620 
6487620 
10

变量a 本质上代表一个存储单元。CPU通过该存储单元的地址访问该存储单元中的数据。
所以a本来代表两个值:存储单元的地址和储单元中的数据。
于是就有了二异性。为了消除这种二义性,C语言规定a表示存储单元中的数据,&a表示存储单元的地址

a存储单元中的数据可以是一个普通数值,也可以是另一个存储单元的地址,比如:a = &b; 语句就是将b的存储单元的地址存入a存储单元中。
C语言规定a代表a中存储的地址对应的存储单元中的数据,也就是访问a就等于访问b,于是*a提供了通过a访问b中的数据的手段。

a表示a对应的存储单元中的数据。
&a表示a对应的存储单元的地址。
a表示:首先,要求a对应的存储单元中的数据 一定是另一个存储单元的地址。
于是,
a表示另一个存储单元中的数据

当a声明的类型是int时,a中存储的是一个整数数值,通过a可以访问(读取或修改)这个数值。 
当a声明的类型是int *时,a中存储的是一个存储单元的地址,而该存储单元中存储的数据是一个整数数值;通过*a可以访问(读取或修改)这个数值。a == &*a 都是该存储单元的地址。 
当a声明的类型是int**时,a中存储的是一个存储单元的地址,而该存储单元中存储的数据是另外一个存储单元的地址,另外这个存储单元中存储的是一个整数数值;通过**a可以访问(读取或修改)这个数值。 
…
最后,在C语言里地址叫指针。还有,在C语言中的数组本质上其实也是指针,即:*a 等同于 a[]。


//先解引用第一个地址(*phead),然后得到一个值(值是一个地址)类型是 PHONE *,所以是PHONE*( *phead )
int init(PHONE **head)
{
	PHONE *newnode = (PHONE*)malloc(sizeof(PHONE));
	if(NULL == newnode)
	{
		return -1;
	}
	
	newnode->next = NULL;
	*head = newnode;
	return 0;
}

/*
定义结构指针变量的一般形式
PHONE* head  -->结构名 * 结构指针变量名
通过结构指针间接访问成员值
访问的一般形式:
(*结构指针变量). 成员名 或 结构指针变量 -> 成员名
如:
(*head).name
head->name
*/
int create(PHONE *head)
{
	PHONE *p;
	p = head;
	PHONE *newP = (PHONE*)malloc(sizeof(PHONE));
	if(newP == NULL)
	{
		return -1;
	}
	
	printf("\33[0;34m请输入信息\33[0m\n");
    srand((unsigned)time(NULL));
    newP->id = rand() %100;
    
    printf("\33[0;34m名字\33[0m\n");
    printf("name :\n");
    scanf("%s",newP->name);
	printf("\33[0;34m电话号码\33[0m\n");
    scanf("%s",newP->phone_number);
	printf("\33[0;34m家庭地址\33[0m\n");
    scanf("%s",newP->home_address);
	printf("\33[0;34m公司号码\33[0m\n");
    scanf("%s",newP->company_number);
    
    newP->next = NULL;
    while(head->next != NULL)
    {
    	head = head->next;
    }
    head->next = newP;
    
    printf("\33[0;32m  create!  \33[0m\n");
	getchar();
	getchar();
    head = p;
}

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;
}

//a = a | (1<<n); --> a |= (1<<n)     输出高电平

        //b = b & ~(1<<n); --> a & = ~(1<<n)   输出低电平

        /*
           1 << n 向左移位  1左移n位    n << 1   n左移1位

        * & 与 (都是1时,结果才为1)  1&1=1  1&0=0  0&0=0
        *
        * | 或  (只要有1,那么就是1) 1|1=1  1|0=1
        *
        *  ^ 异或 (只要一样结果就是0) 0^0=0, 1^0=1, 0^1=1, 1^1=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一样使用这个变量了。

指针数组

posted @ 2022-08-01 19:27  僵小七  阅读(44)  评论(0编辑  收藏  举报