C语言指针的常见问题
1
值传递
下面看一个列子,student结构体中包含该学生的各种信息,我们在change函数中对其进行部分修改,再在主函数中输出其结果
#include<stdio.h> #include<string.h> #define format "%d\n%s\n%f\n%f\n%f\n" struct student { int num; char name[20]; float score[3]; }; void change( struct student stu ); int main() { struct student stu; stu.num = 12345; strcpy(stu.name, "Tom"); stu.score[0] = 67.5; stu.score[1] = 89; stu.score[2] = 78.6; change(stu); printf(format, stu.num, stu.name, stu.score[0], stu.score[1],stu.score[2]); printf("\n"); return 0; } void change(struct student stu) { stu.score[0] = 100; strcpy(stu.name, "jerry"); }
最终输出的值并未改变。。
地址传递
#include<stdio.h> #define format "%d\n%s\n%f\n%f\n%f\n" struct student { int num; char name[20]; float score[3]; }; void change( struct student* stu ); int main() { struct student stu; stu.num = 12345; strcpy(stu.name, "Tom"); stu.score[0] = 67.5; stu.score[1] = 89; stu.score[2] = 78.6; change(&stu); printf(format, stu.num, stu.name, stu.score[0], stu.score[1],stu.score[2]); printf("\n"); return 0; } void change(struct student* p) { p->score[0] = 100; strcpy(p->name, "jerry"); }
可以看到,通过地址传递修改了结构体内的数据
用&stu做实参,&stu是结构体变量stu的地址。在调用函数时将该地址传送给形参p(p是指针变量)。这样p就指向stu。
在change函数中改变结构体内成员的值,在主函数中就输出了改变后的值
2
使用 sum()函数。该程序打印原始数 组的大小和表示该数组的函数形参的大小(如果你的编译器不支持用转换说 明%zd打印sizeof返回值,可以用%u或%lu来代替)。
// sum_arr1.c -- 数组元素之和 // 如果编译器不支持 %zd,用 %u 或 %lu 替换它 #include <stdio.h> #define SIZE 10 int sum(int ar[], int n); int main(void) { int marbles[SIZE] = { 20, 10, 5, 39, 4, 16, 19, 26, 31, 20 }; long answer; answer = sum(marbles, SIZE); printf("The total number of marbles is %ld.\n", answer); printf("The size of marbles is %zd bytes.\n", sizeof marbles); return 0; } int sum(int ar[], int n) // 这个数组的大小是? { int i; int total = 0; for (i = 0; i < n; i++) total += ar[i]; printf("The size of ar is %zd bytes.\n", sizeof ar); return total; }
该程序的输出如下: The size of ar is 8 bytes. The total number of marbles is 190. The size of marbles is 40 bytes.
注意,marbles的大小是40字节。这没问题,因为marbles内含10个int类 型的值,每个值占4字节,所以整个marbles的大小是40字节。但是,ar才8字 节。这是因为ar并不是数组本身,它是一个指向 marbles 数组首元素的指 针。我们的系统中用 8 字节储存地址,所以指针变量的大小是 8字节(其他 系统中地址的大小可能不是8字节)。简而言之,在程序清单10.10中, marbles是一个数组, ar是一个指向marbles数组首元素的指针,利用C中数组 和指针的特殊关系,可以用数组表示法来表示指针ar。
3
传递地址会导致一些问题。C 通常都按值传递数据,因为这样做可以保 证数据的完整性。如果函数使用的是原始数据的副本,就不会意外修改原始 数据。但是,处理数组的函数通常都需要使用原始数据,因此这样的函数可 以修改原数组。有时,这正是我们需要的。例如,下面的函数给数组的每个 元素都加上一个相同的值:
void add_to(double ar[], int n, double val) { int i; for (i = 0; i < n; i++) ar[i] += val; }
因此,调用该函数后,prices数组中的每个元素的值都增加了2.5:
add_to(prices, 100, 2.50);
该函数修改了数组中的数据。之所以可以这样做,是因为函数通过指针 直接使用了原始数据。
ANSI C提供 了一种预防手段。如果函数的意图不是修改数组中的数据内容,那么在函数 原型和函数定义中声明形式参数时应使用关键字const。例如,sum()函数的 原型和定义如下:
int sum(const int ar[], int n); /* 函数原型 */ int sum(const int ar[], int n) /* 函数定义 */ { int i; int total = 0; for( i = 0; i < n; i++) total += ar[i]; return total; }
以上代码中的const告诉编译器,该函数不能修改ar指向的数组中的内 容。如果在函数中不小心使用类似ar[i]++的表达式,编译器会捕获这个错 误,并生成一条错误信息。
4
在C语言中,当你传递一个指针给一个函数,函数接收的是这个指针的副本。所以,如果你在函数内部将这个副本置空,原始指针(在函数外部的)并不会受到影响。
#include <stdio.h> void setNull(int* ptr) { // 将指针指向的地址设为 NULL ptr = NULL; } int main() { int x = 123; int* p = &x; printf("p points to %d\n", *p); // 输出 123 printf("p points : %p\n", p); // 输出 setNull(p); // 置空指针 printf("p points : %p\n", p); // 输出 0,即 NULL printf("p still exists\n"); // 输出 p still exists return 0; }
输出结果
p points to 123 p points : 0x7fff7900dfbc p points : 0x7fff7900dfbc p still exists
本文来自博客园,作者:开源侠,转载请注明原文链接:https://www.cnblogs.com/cyj22/p/17577051.html
微信公众号:青衫换酒吃