C语言程序设计--指针基础

时间:2023-03-09 23:43:57
C语言程序设计--指针基础

指针




指针是一种特殊变量(存储内存地址)。当然它本身也是占用内存的,所以会带来一个问题,那就是指针存在以下概念:指针的类型(int* 一个整型指针),指针指向的类型(int* p = 5, 说明指针p指向了一个整型),指针的值就是内存中5的存储地址,指针的内存地址就是存储指针占用内存的地址。下面我们来分数据类型学习指针,这里只介绍常用指针,不涉及和数组相关的指针(在数据博客中会讲解)、字符串指针的完整讲解(在字符串博客中会讲解)、还有指针的指针,也不涉及。本博客C编译标准以GNU为准,不一定遵从C99,更不一定符合Windows查下的C编译器的结果。

![](https://img2018.cnblogs.com/blog/1070321/201812/1070321-20181225143010954-930409011.png)

基本数据类型



1、整型


整型指针可以在定义时候直接初始化赋值,经过测试double和float并不支持该赋值方式。

int* p_integer = 5;

也可以通过指针等于一个变量的引用的方式赋值;例如

int var_integer = 5;
int *p_integer;
p_integer = &var_integer;

调用方式也很简单,直接p_integer是地址,&p_integer代表的是存储这个指针的内存的地址,*p_integer代表的就是值了,如下文代码所示

//整型指针
int *integer1; //定义一个整型指针
int *integer2 = 10; //定义初始化一个整型指针赋值
int var_int = 5;
integer1 = &var_int;//赋值
/*调用整型指针*/
printf("%d\n", integer1);//打印integer1的地址,直接使用指针是地址
printf("%d\n", &integer2);//打印integer2的地址,引用指针也是地址,是存储指针的内存的地址
printf("%d\n", *integer1);//打印数值,*指针名调用的是数值
printf("%d\n", &var_int);//也是地址,因为赋值的原因,这个地址就是指针integer1的地址

浮点、双精度类型


赋值方式不支持定义的时候直接初始化

//浮点数指针
double var_dou = 6.32;
double *p_dou;
p_dou = &var_dou;
float var_flo = 7.10;
float *p_flo;
p_flo= &var_flo;

调用方式也很简单,浮点数和双精度其实和整型指针差别不大,不做过多的详细叙述

//double *p = 6.32; 这是错误的
printf("%d\n", p_dou);//打印p_dou的地址,直接使用指针是地址
printf("%d\n", p_flo);//打印p_flo的地址,直接使用指针是地址,引用指针是存指针这个地址的指针存储在内存中的位置
printf("%d\n", &p_flo);//打印的是p_flo存储空间的地址
printf("%f\n", *p_dou);//打印数值,*指针名调用的是数值
printf("%d\n", &var_flo);//也是地址,因为赋值的原因,这个地址就是指针p_flo的地址

字符、字符串类型指针


字符、字符串类型指针简要,定义和赋值,很简单,注意对字符串来讲,实际上是一个char数组。这个地方在做字符串操作的时候,传进函数的参数有要求,例如strcat,一定要传数组名,不能随意传入,有坑。

char *p_char = 'a';//这是一个字符指针,指针指向a这个字符,没啥问题。
char *p_str = "abcd";//字符串指针,指针保存的地址是首字母的内存地址
char var_str[10] = "asdf";
char *p_str;
p_str = &var_str

调用也不难,这里注意两个问题,一个是在做一些操作时候,数组名带有数据size信息的,直接定义的指针没有size信息,也意味着没有多余的空间,所以strcat这类函数会报段错误。同理数组大小不够也是一样。第二。数组首地址也就是数组名的地址也是指向字符串(字符数组的首地址),在这个时候*指针表达的是第一个字符。

char *p_str1 = "abcd";//定义字符串,并赋值;
char array[10] = "abcdefg";
char *p_str2;
p_str2 = array;//给字符串(字符数组)的首地址也就是数组的名字,赋值字符串
char *p_char = 'a';//赋值字符
printf("%s\n", p_str1);//打印p_str1字符串
printf("%d\n", &p_str2);//打印p_str2的地址,直接使用指针是地址,引用指针是存指针这个地址的指针存储在内存中的位置
printf("%c\n", *p_str1);//打印第一个字符
//printf("%x\n", *p_char);//没找到这个到底输出啥?bug-1
printf("%d\n", &p_char);//打印地址,因为赋值的原因,这个地址就是指针'a'的地址
printf("%c\n", p_char);//打印唯一一个字符

复杂数据结构的指针



结构体


定义和赋值

typedef struct Student {
char name[10];
int age;
}student;
struct Student * p_struct;
student * p_struct;
strcpy(p_struct->name, "Tom");
p_struct->age = 10;
student var_struct = {"Bill", 8};
p_struct = &var_struct

调用也不难

student var_stu = {"Tom", 8};
student *p_stu;
p_stu = &var_stu;//赋值
printf("%s\n",p_stu->name);//名字
printf("%d\n",p_stu->age);//年龄
printf("%d\n",p_stu);//结构体对象地址
printf("%d\n",&var_stu);//结构体对象地址

枚举体和共用体

和结构体类似,内部字段调用也是用->,定义和赋值没啥差别

//枚举体、共用体指针
typedef enum Gender {male, female}gender;
gender var_enum = male;
gender *p_enum1 = female;
gender *p_enum2;
p_enum2 = &var_enum;
//printf("%d", *p_enum1);
printf("%d\n", p_enum1);//枚举体的值
printf("%d\n", &p_enum2);//指针地址
//printf("%d", *p_enum2);
printf("%d\n", p_enum2);//枚举体的值
printf("%d\n", &var_enum);//枚举体变量的地址
printf("******************************************************************\n");
typedef union ID {char _id_char[10]; int _id_int;}id;//定义共用体,一个数据结构,一个变量多种数据类型,但是在同一时刻只能有一种数据类型可以被使用。
id __id;
__id._id_int = 8;
printf("%d\n", __id._id_int);
id *p_uni;
p_uni = &__id;
p_uni->_id_int = 6;
printf("%d\n", p_uni->_id_int);
printf("******************************************************************\n");

特殊类型指针



void指针


常见于在函数中参数可以为任意类型指针时候使用,在函数体内再做类型转换

void *buffer;
char *p_addr = (char *)buffer;

函数指针

指针函数是返回指针的函数,函数指针如下,并不是返回指针的函数,而是用于类似python的map、reduce、lamdba等功能的函数动态选择时候。

char* (*func)(char *result, char *str1,char *str2);

char* string_add(char *result,char *str1,char *str2){
//char result[20] = "";
printf("%s\n", str1);
printf("%s\n", str2);
strcat(result, str1);
strcat(result, str2);
printf("%s\n", result);
return result;
}
//使用
func = string_add;
char result[20] = "";
printf("%s\n", (*func)(result,"T","ED"));