passing by preference
passing by value
值互换:
#include <stdio.h>
void swap(int a, int b);
int main(void)
{
// 键盘录入两整数
int x, y;
printf("请输入两个整数:");
scanf("%d %d", &x, &y);
printf("交换前 x = %i, y = %i\n", x, y);
// 值互换
swap(x, y); /* 实现:x和y值互换 */
printf("交换后 x = %i, y = %i\n", x, y);
}
void swap(int a, int b) /* 按值传递 */
{
int temp = a;
a = b;
b = temp;
}
结果:
我们发现,值并么有发生互换,这是因为,a 和 b的声明周期只存在于{}内,当调用完函数后出栈,就没了,并不会影响到原始数据,即main函数中的’x’和’y’
那么如果,我们定义的函数想要对原始数据进行修改,而非只是从函数那里得到一个结果的话,要怎么做呢?
指针,指针作用其二——处理地址处数据,即可以对地址处的数据进行修改和取出;因此,我们不妨获取main函数中’x’和’y’的内存地址,然后再进行互换
void swap(int* a, int* b) /* 按引用传递 */
{
int temp = *a; /* 临时变量,获取地址处数据 */
*a = *b;
*b = temp;
}
结果:
当然,要传入内存地址,main函数中的一处仍需修改:
/* 以前版本
* swap(x, y);
* /
*
// 新版本
swap(&x, &y); /* 传递的是x和y的内存地址 */
指针呢?
如果我们需要通过函数改变main函数中的指针变量时,又如何处理?
和上面的值互换类似,指针亦是一种变量类型
我们可将,指针看做一种新的变量类型
那么按引用传递,就类似于int、char、float…
因此,若我们想在函数中改变一个指针本身(即,让指针指向不同的内存地址),你需要传递该指针的地址。这通常被称为“指向指针的指针”(pointer to pointer)。通过传递指针的地址,函数可以修改调用者指针的值。
例、实现函数(结构体指针)
push_front(value) —— 添加元素到链表的首部
结果:
图解:
代码:
// 单向链表,无尾指针
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int number; /* 存储数据 */
struct node* next; /* 指向下一个节点 */
} node;
node* creatLink(int arry[], int length); /* 创建链表, length为数组长度 */
void printLink(node* list); /* 打印链表中的元素 */
void freeLink(node* list); /* 释放链表 */
void push_front(int value, node** list); /* 在链表首,添加元素;为什么是void?因为passing by preference */
int main(void)
{
// 创建链表
int arry[] = {1, 2, 3, 4}; /* 修改数组的值,可改变链表数据;注意:是整数数组! */
int length = sizeof(arry) / sizeof(arry[0]); /* 获取整数数组长度 */
node* list = creatLink(arry, length);
// 打印链表
printLink(list);
// 在链表前添加元素
push_front(666, &list); /* 将666添加到链表首 */
printf("新");
printLink(list);
// 释放链表
freeLink(list);
}
void push_front(int value, node** list)
{
node* n = malloc(sizeof(node));
n->number = value;
n->next = *list;
*list = n;
}
node* creatLink(int arry[], int length)
{
// 创建链表
node* list = NULL; /* 无尾指针;list为链表头部 */
for(int i = 0; i < length; ++i)
{
node* n = malloc(sizeof(node)); /* 创建节点 */
n->number = arry[i];
n->next = NULL;
// 链表
if(list == NULL)
list = n; /* 链表的第一个元素 */
else
{
node* ptr;
for(ptr = list; ptr->next != NULL; ptr = ptr->next) /* 将链表的最后一个元素指向新的节点 */
; /* 只需遍历到链表的最后一个元素,无需方法体 */
ptr->next = n;
}
}
return list;
}
void printLink(node* list)
{
if(list == NULL) /* 空链表 */
printf("链表中的元素有:[]\n");
else
{
node* ptr;
printf("链表中的元素有:[");
for(ptr = list; ptr->next != NULL; ptr = ptr->next) /* 遍历到倒数第二个元素 */
printf("%d, ", ptr->number);
printf("%d]\n", ptr->number);
}
}
void freeLink(node* list)
{
// free链表:类似于吃糖豆人——先得到下一个节点,再释放前一个节点
node* ptr = list;
while(ptr != NULL)
{
ptr = ptr->next;
free(list);
list = ptr;
}
}