目录
每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。
10.1 指针的说明
指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。
就像其他变量或常量一样,必须在使用指针存储其他变量地址之前,对其进行声明。
type *var-name;
type 是指针的基类型,它必须是一个有效的 C 数据类型,var-name 是指针变量的名称。
用来声明指针的星号 * 与乘法中使用的星号是相同的。
但是,在这个语句中,星号是用来指定一个变量是指针。
所有指针的值的实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,都是一样的,都是一个代表内存地址的长的十六进制数。
10.2 使用指针
使用指针时会频繁进行以下几个操作:
定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值。
这些是通过使用一元运算符 * 来返回位于操作数所指定地址的变量的值。
/*-----------------------------------------------------------------------*/
#include <stdio.h>
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 main 的功能描述:
* 使用指针并获取相关数据.
* @param[in] void
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
int main()
{
int var = 20; //实际变量的声明
int *ip; //指针变量的声明
ip = &var; //在指针变量中存储 var 的地址
printf("Address of var variable: 0x%x\n", &var);
/* 在指针变量中存储的地址 */
printf("Address stored in ip variable: 0x%x\n", ip);
/* 使用指针访问值 */
printf("Value of *ip variable: %d\n", *ip);
return 0;
}
/*-----------------------------------------------------------------------*/
Visual Studio 运行结果:
10.3 C 中的 NULL 指针
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。
赋为 NULL 值的指针被称为空指针。
NULL 指针是一个定义在标准库中的值为零的常量。
/*-----------------------------------------------------------------------*/
#include <stdio.h>
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 main 的功能描述:
* 使用NULL指针.
* @param[in] void
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
int main()
{
int *ptr = NULL;
printf("ptr 的值是 %x\n", ptr);
return 0;
}
/*-----------------------------------------------------------------------*/
Visual Studio 运行结果:
在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。
然而,内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置。
但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。
如需检查一个空指针,使用 if 语句,如下所示:
if(ptr) /* 如果 p 非空,则完成 */
if(!ptr) /* 如果 p 为空,则完成 */
10.4 指针的算术运算
可以对指针进行四种算术运算:++、--、+、-
/*-----------------------------------------------------------------------*/
#include <stdio.h>
/*-----------------------------------------------------------------------*/
/* 全局变量 */
const int MAX = 3;
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 main 的功能描述:
* 指针的算术运算.
* @param[in] void
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
int main()
{
int var[] = { 10, 100, 200 };
int i, *ptr;
/* 指针中的数组地址 */
ptr = var;
for (i = 0; i < MAX; i++)
{
printf("Address of var[%d] = %x\n", i, ptr);
printf("Value of var[%d] = %d\n", i, *ptr);
/* 移动到下一个位置 */
ptr++;
}
return 0;
}
/*-----------------------------------------------------------------------*/
Visual Studio 运行结果:
10.5 指针数组
可以定义用来存储指针的数组。
int *ptr[MAX];
ptr 声明为一个数组,由 MAX 个整数指针组成。
因此,ptr 中的每个元素,都是一个指向 int 值的指针。
int a[10] = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
int *p; //定义p为指向整型变量的指针变量
p = &a[0]; //把a[0]元素的地址赋值给指针变量p
// 等价
p = a; //p的值是a首元素的地址
//定义指针变量时可以对它初始化
int *p = &a[0];
//也可以写成:
int *p = a;
有一个整型数组a,有10个元素,要求输出数组中的全部元素
10.5.1. 下标法
/*-----------------------------------------------------------------------*/
#include <stdio.h>
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 main 的功能描述:
* 使用数组下标法,
* 整型数组a,有10个元素,要求输出数组中的全部元素.
* @param[in] void
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
int main()
{
int a[10] = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
int i;
printf("Please output 10 numbers:");
for (i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
/*-----------------------------------------------------------------------*/
Visual Studio 运行结果:
10.5.2. 指针法
/*-----------------------------------------------------------------------*/
#include <stdio.h>
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 main 的功能描述:
* 使用指针法,
* 整型数组a,有10个元素,要求输出数组中的全部元素.
* @param[in] void
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
int main()
{
int a[10] = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
int i, *p;
printf("Please output 10 numbers:");
for (p = a; p < (a + 10); p++)
{
printf("%d ", *p);
}
printf("\n");
return 0;
}
/*-----------------------------------------------------------------------*/
Visual Studio 运行结果:
10.5.3 指针数组存储字符串
也可以用一个指向字符的指针数组来存储一个字符串列表,如下:
/*-----------------------------------------------------------------------*/
#include <stdio.h>
/*-----------------------------------------------------------------------*/
/* 全局变量 */
const int MAX = 4;
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 main 的功能描述:
* 一个指向字符的指针数组来存储一个字符串列表.
* @param[in] void
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
int main()
{
char *names[] =
{
"AAAAA",
"BBBBB",
"CCCCC",
"DDDDD",
};
int i = 0;
for (i = 0; i < MAX; i++)
{
printf("Value of names[%d] = %s\n", i, names[i]);
}
return 0;
}
/*-----------------------------------------------------------------------*/
Visual Studio 运行结果:
10.6 指向指针的指针
C 允许指向指针的指针。
指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。
通常,一个指针包含一个变量的地址。
当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。
int **ptr;
10.7 指针作函数参数
通过引用或地址传递参数,使传递的参数在调用函数中被改变。
C 语言允许传递指针给函数,只需要简单地声明函数参数为指针类型即可。
10.7.1 函数参数使用数组名a
/*-----------------------------------------------------------------------*/
#include <stdio.h>
/*-----------------------------------------------------------------------*/
/* 函数声明 */
void Sort(int x[], int n);
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 main 的功能描述:
* 将数组a中n个整数从小到大存放.
* @param[in] void
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
int main()
{
int i = 0;
int a[10] = { 3, 7, 9, 11, 0, 6, 7, 5, 4, 2 };
/*-----------------------*/
printf("The original array: \n");
for (i = 0; i < 10; i++)
printf("%d ", a[i]);
printf("\n");
/*-----------------------*/
Sort(a, 10); //功能函数调用
/*-----------------------*/
printf("The array has been sort: \n");
for (i = 0; i < 10; i++)
printf("%d ", a[i]);
printf("\n");
/*-----------------------*/
return 0;
}
/*-----------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 Sort 的功能描述:
* 功能函数.
* @param[in]
* int x[] 输入的数组标
* int n 待排序数据个数
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
void Sort(int x[], int n)
{
int i = 0, j = 0;
int k1 = 0;
for (i = 0; i < n-1; i++)
{
k1 = x[i];
for (j = i+1; j< n ; j++)
{
if (k1>x[j])
{
x[i] = x[j];
x[j] = k1;
k1 = x[i];
}
}
}
}
/*-----------------------------------------------------------------------*/
Visual Studio 运行结果:
10.7.2 函数参数使用指针变量
/*-----------------------------------------------------------------------*/
#include <stdio.h>
/*-----------------------------------------------------------------------*/
/* 函数声明 */
void Sort(int *x, int n);
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 main 的功能描述:
* 将数组a中n个整数从小到大存放.
* @param[in] void
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
int main()
{
int i = 0;
int a[10] = { 3, 7, 9, 11, 0, 6, 7, 5, 4, 2 };
/*-----------------------*/
printf("The original array: \n");
for (i = 0; i < 10; i++)
printf("%d ", a[i]);
printf("\n");
/*-----------------------*/
Sort(a, 10); //功能函数调用
/*-----------------------*/
printf("The array has been sort: \n");
for (i = 0; i < 10; i++)
printf("%d ", a[i]);
printf("\n");
/*-----------------------*/
return 0;
}
/*-----------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 Sort 的功能描述:
* 功能函数.
* @param[in]
* int x[] 输入的数组标
* int n 待排序数据个数
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
void Sort(int *x, int n)
{
int i = 0, j = 0;
int k1 = 0;
for (i = 0; i < n-1; i++)
{
k1 = *(x+i);
for (j = i+1; j< n ; j++)
{
if (k1>*(x + j))
{
*(x + i) = *(x + j);
*(x + j) = k1;
k1 = *(x + i);
}
}
}
}
/*-----------------------------------------------------------------------*/
Visual Studio 运行结果:
10.7.3 指针变量作实参
/*-----------------------------------------------------------------------*/
#include <stdio.h>
/*-----------------------------------------------------------------------*/
/* 函数声明 */
void Sort(int *x, int n);
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 main 的功能描述:
* 将数组a中n个整数从小到大存放.
* @param[in] void
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
int main()
{
int i = 0;
int a[10] = { 3, 7, 9, 11, 0, 6, 7, 5, 4, 2 };
int *p = a;//指针变量指向a[0]
/*-----------------------*/
printf("The original array: \n");
for (i = 0; i < 10; i++)
printf("%d ", a[i]);
printf("\n");
/*-----------------------*/
Sort(p, 10); //功能函数调用
/*-----------------------*/
printf("The array has been sort: \n");
for (p = a; p < a+10; p++)
printf("%d ", *p);
printf("\n");
/*-----------------------*/
return 0;
}
/*-----------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 Sort 的功能描述:
* 功能函数.
* @param[in]
* int x[] 输入的数组标
* int n 待排序数据个数
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
void Sort(int *x, int n)
{
int i = 0, j = 0;
int k1 = 0;
for (i = 0; i < n-1; i++)
{
k1 = *(x+i);
for (j = i+1; j< n ; j++)
{
if (k1>*(x + j))
{
*(x + i) = *(x + j);
*(x + j) = k1;
k1 = *(x + i);
}
}
}
}
/*-----------------------------------------------------------------------*/
Visual Studio 运行结果:
10.8 从函数返回指针
C 允许函数返回指针到局部变量、静态变量和动态内存分配。
C 允许从函数返回指针。为了做到这点,必须声明一个返回指针的函数。
另外,C 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量。
下面的函数会生成 10 个随机数,并使用表示指针的数组名(即第一个数组元素的地址)来返回它们。
/*-----------------------------------------------------------------------*/
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
/*-----------------------------------------------------------------------*/
/* 函数声明 */
int *getRandom();
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 main 的功能描述:
* 将使用表示指针的数组名(即第一个数组元素的地址)来返回生成的数组.
* @param[in] void
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
int main()
{
int i;
int *p=NULL; //一个指向整数的指针
/*-----------------------*/
p = getRandom();
/*-----------------------*/
for (i = 0; i < 10; i++)
{
printf("*(p + [%d]) : %d\n", i, *(p + i));
}
/*-----------------------*/
return 0;
}
/*-----------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 getRandom 的功能描述:
* 要生成和返回随机数的函数.
* @param[in] void
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
int *getRandom()
{
int i;
static int r[10];
srand((unsigned)time(NULL)); //设置种子
for (i = 0; i < 10; i++)
{
r[i] = rand();
printf("%d\n", r[i]);
}
return r;
}
/*-----------------------------------------------------------------------*/
Visual Studio 运行结果:
10.9 指针处理链表
10.9.1 静态链表
/*-----------------------------------------------------------------------*/
#include <stdio.h>
/*-----------------------------------------------------------------------*/
/* 创建结构体 */
struct Student //声明结构体类型struct Student
{
int num;
float score;
struct Student *next;
};
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 main 的功能描述:
* 使用指针处理静态链表.
* @param[in] void
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
int main()
{
struct Student a, b, c, *head, *p; //定义3个结构体变量a,b,c作为链表的结点
a.num = 101; a.score = 89.5; //对结点a的num和score成员赋值
b.num = 103; b.score = 90;
c.num = 107; c.score = 85;
head = &a; //将结点a的起始地址赋给头指针head
a.next = &b;
b.next = &c;
c.next = NULL; //c结点的next成员不存放其他结点地址
p = head; //使p指向a结点
do
{
printf("%ld %5.1f\n", p->num, p->score);
p = p->next; //输出完c结点后p的值为NULL,循环终止
} while (p != NULL);
return 0;
}
/*-----------------------------------------------------------------------*/
Visual Studio 运行结果:
10.9.2 动态链表
/*-----------------------------------------------------------------------*/
#include <stdio.h>
#include <malloc.h>
/*-----------------------------------------------------------------------*/
/* 创建结构体 */
struct Student
{
int num;
float score;
struct Student *next;
};
/*-----------------------*/
#define LEN sizeof(struct Student) //获取结构体长度
int n; //链表单元计数器
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 creat 的功能描述:
* 建立链表的函数.
* @param[in] void
*
* @return
* struct Student *head 所配置的链表
*
* @implements 低层需求标识号 XXXX
*/
struct Student *creat()
{
struct Student *head = NULL; //初始化头指针为空
struct Student *p1; //p1 用于遍历链表
struct Student *p2; //p2 用于连接链表节点
n = 0; //初始化链表单元计数器
p1 = p2 = (struct Student*) malloc(LEN); //先动态分配内存空间,并将 p1 和 p2 指向它
/*-----------------------*/
scanf("%ld,%f", &p1->num, &p1->score); //p1是当前要录入数据的指针
/*-----------------------*/
while (p1->num != 0)//当输入0值时,跳出链表配置的输入
{
n = n + 1;
if (n == 1)//将头指针指向链表第一个节点
{
head = p1;
}
else//连接上一个节点和当前节点
{
p2->next = p1;
}
p2 = p1;//更新 p2 为当前节点,以便连接下一个节点
p1 = (struct Student*)malloc(LEN);//为下一个节点分配内存空间
scanf("%ld,%f", &p1->num, &p1->score);
}
/*-----------------------*/
p2->next = NULL; //最后一个节点的 next 指针为 NULL,标志链表结束!
/*-----------------------*/
return(head);
}
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 print 的功能描述:
* 输出链表的函数.
* @param[in]
* struct Student *head 所配置的链表
*
* @return void
*
* @implements 低层需求标识号 XXXX
*/
void print(struct Student *head)
{
struct Student *p;
p = head;
/*-----------------------*/
printf("\nNow,These %d records are:\n", n); //输出链表元素实际个数
/*-----------------------*/
for (p = head; p != NULL; p = p->next)
{
printf("%ld %5.1f\n", p->num, p->score);
}
/*-----------------------*/
}
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 main 的功能描述:
* 使用指针处理动态链表.
* @param[in] void
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
int main()
{
struct Student *head; //创建链表头指针
head = creat(); //配置链表内容
print(head); //输出链表内容
free(head); //释放指针内存
return 0;
}
/*-----------------------------------------------------------------------*/
Visual Studio 运行结果:
10.10 指向函数的指针
/*-----------------------------------------------------------------------*/
#include <stdio.h>
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 main 的功能描述:
* 求两个数中的最大值.
* @param[in] void
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
int main()
{
int max(int, int); //函数声明
int(*p)(int, int); //定义指向函数的指针变量p
int a, b, c;
p = max; //使p指向函数
printf("Please enter a and b:");
scanf("%d,%d", &a, &b);
c = (*p)(a, b); //通过指针变量调用函数
printf("a=%d\nb=%d\nmax=%d\n", a, b, c);
return 0;
}
/*-----------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/*
* @brief
* 关于 max 的功能描述:
* 功能函数.
* @param[in]
* int x 输入的值1
* int y 输入的值2
*
* @return return 0
*
* @implements 低层需求标识号 XXXX
*/
int max(int x, int y)
{
int z;
if (x > y)
{
z = x;
}
else
{
z = y;
}
return (z);
}
/*-----------------------------------------------------------------------*/
Visual Studio 运行结果:
非常感谢您的支持!创作不易,转发备注出处!
自用展示内容,不定期更新维护内容,让我们把 C开发 变得更专业。
十年开发基本功,常年开班收徒(一年学徒制度),每年10个名额。
商业合作加微信,项目接包与外包。