C语言指针

C语言指针是C语言非常重要的一个概念,我们可以通过指针去读取内存的数据。
声明方式:

type *Ptr;
type 可以是任何可以用类型。

虽然我们通过 int *Ptr,声明了一个指向int类型的指针,但是指针的占用的实际内存,并不与int相同。

#include <stdio.h>
int main(void)
{
	int arr[][5] = {10, 20, 30, 40, 50, 60, 70};
	int *ptr;
	
	printf("array is using %ld bytes \n", sizeof(arr));
	printf("int uses %ld bytes\n", sizeof(arr));
	printf("Ponit uses %ld bytes \n", sizeof(arr));

	return 0;
}
指针的初始化
int *Ptr, a;
Ptr = &a;

&a的意思就是取到变量a的地址,Ptr = &a,就是把指针的值改为a的地址,*Ptr就是取a的值。
另外,地址操作符&,不能用在常数(&20),表达式(&(a+b)),或者是register类型的变量,和位领域。它只能应用在内存的一个对象,比如变量,数组和函数。

空指针

当指针被声明后,它就会给出一个任意值。事实上,这个值是内存当中的垃圾,最好办法就是将ptr的值变为NULL。NULL是一个宏,定义在stdio.h文件中。虽然我们也可以给ptr赋值0,但是最好还是通过这个NULL宏定义来设置空指针。

#include <stdio.h>
int main(void)
{
	int *ptr;
	
	printf("Addr = %p\n", ptr);
	ptr = NULL;
	printf("Addr = %p\n", ptr);

	return 0;
}

结果:

Addr = 0x7ffd7ea4be70
Addr = (nil)
使用一个指针
int *Ptr,a;
a = 10;
Ptr = &a;

Ptr表示的是内存的地址,*Ptr意思是读取这个内存地址内存放的数据。
当然比较复杂的还有**Ptr,同理,*Ptr的意思这个内存的存放的内容,这里面可以是int float dobule,char…但是这个是个特列,*Ptr存放的又是一个指针,**Ptr的意思就是,在一个内存地址里面存放了一个指针,然后通过这个指针再找到另外一个地址,然后取这个内存里的数据。

值得注意的是 ,在它被废弃前,指针的值必须指向一个有效内存地址,例如一个变量的地址。

在Unix/Linux中通常,当我们的指针错误引用,就会跳出一个“Segmentation fault”错误。
所以,一定要记住在使用指针前,一定要初始化它。

void* Pointer

一个void类型的指针一个可以指向所有类型的广谱指针。任何的指针都可以投向 void* 和返回普通类型,并且在这个过程中,信息不会有任何的丢失。

使用const限定符

为了防止一个指针的指向的值发生变化,我们可以在它的类型前面加上const关键字。

int j,i =10;
const int *ptr;
ptr = &i;  //合法
*ptr = 30; //非法
ptr =&j;   //合法

为了放置指针的变量存放的地址发生变化,我们会在类型后面加上const,但是同时必须在声明的同时进行赋值。

int i, j;
int* const ptr = &i;
ptr = &j;  //非法
*ptr = 30 //合法
指针运算

我们通过指针的加减运算来指向同一个数组的不同元素。

指针和整数

ptr = ptr + n;
如果ptr指向arr[i],n是3,则ptr指向的元素是arr[i+3]

指针数组

这是一个存储指针类型的数组,声明如下:
int *p[3];
这个数组是由3个指向int类型的指针组成。

int *p[3],i=100,j=200,k=300;
p[0] = &i;
p[1] = &j;
p[2] = &k;

二维数组:
char names[][12] = {“First name”, “Second name”, “Third”};
我们声明了一个二维数组,每一行占用12个bytes
如果我们使用指针数组的话:
char *name[] = {“First name”, “Second name”, “Third”};
数组就会自动分配了相对应的内存,这样就会节省内存。

使用指针除了可以节省内存外,还可以提高程序的性能。

指针与二维数组

C语言只有一维数组,二维数组其实也是一维数组的变形。
我们声明一个二维数组:
int a[2][3];
在这个数组中一共是6个地址,我们可以通过指向第一个元素的指针,依次遍历出所有元素的值。
例如:

#include <stdio.h>
int main(void)
{
  int i;
  int a[2][3] = {1,2,3,4,5,6};
  int *ptr;
  ptr = a[0] ;
  
  for(i=0;i<6;i++){
    printf("The a[%d] = %d\n",i,*(ptr+i));
  }

}
函数的指针

当一个函数被定义,编译器就会为之分配内存用来存储他的代码。因此,每一个函数都会像普通变量一样会有一个地址。函数的指针指向这个存储函数代码的内存地址。C处理函数指针跟处理其他普通指针一样。例如,我们可以存储他们在一个变量或者像数组元素一样使用它们,声明的语法如下:
return_type (*pointer_name) (type_param_1 name_1, type_param_2 name_2,
…, type_param_n name_n);

int (*ptr)(int arr[], int size);

ptr被声明为一个指向函数的指针,这个函数接受一个int类型的数组,和一个int变量,最后返回值是一个int类型。

void (*ptr)(double *arr[]);

ptr是指向函数的指针,此函数有一个参数,这个参数是一个double类型的指针数组,此函数没有返回值。

int test(void (*ptr)(int a));

一个名为test的函数,返回值是int。test函数的参数是一个没有返回值的函数,此函数的参数是一个int的变量。

#include <stdio.h>
void test(int a);

int main(void)
{
  void (*ptr)(int a);
  
  ptr = test;
  ptr(10);

  return 0;
}

void test(int a)
{
  printf("The double a is %d\n", a * 2);

}
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void make_rand(void (*ptr)(int evt, int num)); /* Although we could write
make_rand(void  ptr(int  evt,  int  num));,  we  prefer  the  pointer
declaration. */
void handle_event(int evt, int num);
int main(void)
{
	srand(time(NULL));
	make_rand(handle_event);

	return 0;
}

void make_rand(void (*ptr)(int evt, int num))
{
	int i, cnt;
	cnt = 0;

	while(1){
		i = rand();
		cnt++;
		if(i >= 1000 && i <= 2000){
			(*ptr)(cnt, i);
			return;
		}
	}
}

void handle_event(int evt, int num)
{
	printf("Times:%d Num:%d\n", evt, num);
}
函数指针的数组

通俗的讲就是一个数组,这个数组的元素都是指针,这些指针都指向函数

#include <stdio.h>
int test_1(int a, int b);
int test_2(int a, int b);
int test_3(int a, int b);

int main(void)
{
	int (*ptr[3])(int a, int b);
	int i, j, k;
	ptr[0] = test_1; /* ptr[0] points to the memory address of
	test_1(). */
	ptr[1] = test_2;
	ptr[2] = test_3;
	
	printf("Enter numbers: ");
	scanf("%d%d", &i, &j);
	if(i > 0 && i < 10)
		k = ptr[0](i, j); /* Call the function that ptr[0] points to. We could also write k = (*ptr[0])(i, j). */
	else if(i >= 10 && i < 20)
		k = ptr[1](i, j); /* Call the function that ptr[1] points to. */
	else
		k = ptr[2](i, j); /* Call the function that ptr[2] points to. */
		printf("Val = %d\n", k);
	
	return 0;
}

int test_1(int a, int b)
{
	return a+b;
}

int test_2(int a, int b)
{
	return a-b;
}

int test_3(int a, int b)
{
	return a*b;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值