绝了!这17个C指针**,让无数程序员连夜收藏
今天,咱们来聊聊 C 语言里最让人又爱又恨的东西——指针!别一听到指针就头疼,今天我保证让你看完之后直呼"卧槽,原来还能这么玩!"**一:指针当计算器用你知道吗?指针其实是个天生的数学家!看这个:#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int *p = arr;
printf("原来的值:%d\n", *p); // 输出:10
printf("往后跳一步:%d\n", *(p+1)); // 输出:20
printf("往后跳三步:%d\n", *(p+3)); // 输出:40
return 0;
}
看到没?指针加个数字就能跳到别的位置!就像在数组里蹦迪一样,想跳哪就跳哪。**二:指针的"换身术"这个绝对震撼你三观!两个变量的值,用指针一秒钟就能互换:#include <stdio.h>
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 100, y = 200;
printf("交换前:x=%d, y=%d\n", x, y); // 输出:x=100, y=200
swap(&x, &y);
printf("交换后:x=%d, y=%d\n", x, y); // 输出:x=200, y=100
return0;
}
是不是感觉像变魔术?两个数字眨眼间就换了位置! **三:指针数组——批量管理**想象一下,你有一堆字符串要管理,用指针数组简直不要太爽:#include <stdio.h>
int main() {
constchar *names[] = {"小明", "小红", "小刚", "小美"};
printf("班级名单:\n");
for(int i = 0; i < 4; i++) {
printf("%d. %s\n", i+1, names);
}
// 输出:
// 1. 小明
// 2. 小红
// 3. 小刚
// 4. 小美
return0;
}
一个数组装下所有字符串,想用哪个直接拿,简直是管理神器!**四:函数指针——让函数也能当变量这个**绝对让你大开眼界!函数居然也能用指针指着:#include <stdio.h>
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
int main() {
int (*operation)(int, int); // 声明一个函数指针
operation = add; // 指向加法函数
printf("5 + 3 = %d\n", operation(5, 3)); // 输出:8
operation = multiply; // 指向乘法函数
printf("5 * 3 = %d\n", operation(5, 3)); // 输出:15
return0;
}
看到没?同一个指针,一会儿做加法,一会儿做乘法,简直是变脸高手!**五:动态内存——想要多少给多少这个真的太实用了!想要多大内存,现场申请:#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
printf("你想要几个整数的空间?");
scanf_s("%d", &n);
int* arr = (int*)malloc(n * sizeof(int)); // 动态申请内存
// 填充数据
for (int i = 0; i < n; i++) {
arr = (i + 1) * 10;
}
// 输出结果
printf("动态数组的内容:");
for (int i = 0; i < n; i++) {
printf("%d ", arr);
}
printf("\n");
free(arr); // 记得释放内存!
return0;
}
想要3个就给3个,想要100个就给100个,完全按需分配! **六:指针的指针——套娃游戏这个有点绕,但是很有趣!指针也能被别的指针指着:#include <stdio.h>
int main() {
int num = 42;
int *p1 = # // p1指向num
int **p2 = &p1; // p2指向p1
printf("直接访问:%d\n", num); // 输出:42
printf("一级指针:%d\n", *p1); // 输出:42
printf("二级指针:%d\n", **p2); // 输出:42
// 通过二级指针修改值
**p2 = 100;
printf("修改后的值:%d\n", num); // 输出:100
return0;
}
就像俄罗斯套娃,一层套一层,但最后都能找到那个宝贝!**七:指针遍历字符串——速度飞快用指针遍历字符串,效率杠杠的:#include <stdio.h>
int main() {
char str[] = "Hello World!";
char *p = str;
printf("逐个字符输出:\n");
while(*p != '\0') {
printf("%c ", *p);
p++; // 指针往前走
}
printf("\n");
// 输出:H e l l o W o r l d !
return0;
}
指针一步步往前走,把每个字符都拿到手,简单粗暴!**八:指针数组vs数组指针——双胞胎的区别这两个长得很像,但作用完全不同:#include <stdio.h>
int main() {
// 指针数组:是个数组,里面装的都是指针
char *arr1[] = {"苹果", "香蕉", "橙子"};
// 数组指针:是个指针,指向一个数组
int nums[] = {1, 2, 3, 4, 5};
int (*arr2) = &nums;
printf("指针数组的内容:\n");
for(int i = 0; i < 3; i++) {
printf("%s ", arr1);
}
printf("\n");
printf("数组指针指向的数组:\n");
for(int i = 0; i < 5; i++) {
printf("%d ", (*arr2));
}
printf("\n");
return0;
}
记住:指针数组是装指针的盒子,数组指针是指向盒子的手!**九:指针运算的神奇魔法指针还能做减法运算,算出两个位置的距离:#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int *start = &arr; // 指向20
int *end = &arr; // 指向50
printf("两个指针的距离:%ld个位置\n", end - start); // 输出:3
printf("从%d到%d,中间隔了%ld个数\n", *start, *end, end - start);
return 0;
}
指针一减,立马知道隔了多少个位置,简直是内置的测距仪!**十:void指针——万能胶水这个指针太牛了,什么类型都能指:#include <stdio.h>
int main() {
int num = 100;
float pi = 3.14;
char ch = 'A';
void *magic_ptr; // 万能指针
magic_ptr = #
printf("指向整数:%d\n", *(int*)magic_ptr); // 输出:100
magic_ptr = π
printf("指向小数:%.2f\n", *(float*)magic_ptr); // 输出:3.14
magic_ptr = &ch;
printf("指向字符:%c\n", *(char*)magic_ptr); // 输出:A
return0;
}
一个指针走天下,想指啥就指啥,就是用的时候要记得转换类型! **十一:指针与结构体的完美搭配结构体遇上指针,简直是天作之合:#include <stdio.h>
struct Student {
char name;
int age;
float score;
};
int main() {
struct Student stu = {"小明", 18, 95.5};
struct Student *p = &stu;
// 两种访问方式,效果一样
printf("方式1 - (*p).name: %s\n", (*p).name); // 输出:小明
printf("方式2 - p->name: %s\n", p->name); // 输出:小明
// 修改数据也超简单
p->age = 19;
p->score = 98.0;
printf("修改后:%s今年%d岁,考了%.1f分\n", p->name, p->age, p->score);
return0;
}
用箭头操作符->,写起来简洁得不行!**十二:指针数组做函数跳转表这个**绝了,可以做个简易计算器:#include <stdio.h>
float add(float a, float b) { return a + b; }
float sub(float a, float b) { return a - b; }
float mul(float a, float b) { return a * b; }
float div(float a, float b) { return a / b; }
int main() {
float (*calc[])(float, float) = {add, sub, mul, div};
char ops[] = {'+', '-', '*', '/'};
float a = 10, b = 3;
printf("简易计算器演示:\n");
for(int i = 0; i < 4; i++) {
printf("%.1f %c %.1f = %.2f\n", a, ops, b, calc(a, b));
}
// 输出:
// 10.0 + 3.0 = 13.00
// 10.0 - 3.0 = 7.00
// 10.0 * 3.0 = 30.00
// 10.0 / 3.0 = 3.33
return0;
}
把函数装进数组,想调哪个调哪个,是不是很酷?**十三:const指针的三种姿势const和指针组合,有三种不同的**:#include <stdio.h>
int main() {
int a = 10, b = 20;
// 姿势1:指向常量的指针(指针可变,内容不可变)
constint *p1 = &a;
printf("p1指向:%d\n", *p1); // 输出:10
p1 = &b; // 可以改指向
printf("p1现在指向:%d\n", *p1); // 输出:20
// *p1 = 30; // 这句会报错!不能修改内容
// 姿势2:常量指针(指针不可变,内容可变)
int * const p2 = &a;
*p2 = 30; // 可以修改内容
printf("通过p2修改a:%d\n", a); // 输出:30
// p2 = &b; // 这句会报错!不能改指向
// 姿势3:指向常量的常量指针(都不能变)
constint * const p3 = &a;
printf("p3指向:%d\n", *p3); // 只能读取
// *p3 = 40; // 报错!
// p3 = &b; // 报错!
return0;
}
记住顺口溜:const在前内容定,const在后指针定,前后都有全都定!**十四:指针与malloc的黄金组合动态分配二维数组,这个操作太秀了:#include <stdio.h>
#include <stdlib.h>
int main() {
int rows = 3, cols = 4;
// 分配指针数组
int **matrix = (int**)malloc(rows * sizeof(int*));
// 为每一行分配空间
for(int i = 0; i < rows; i++) {
matrix = (int*)malloc(cols * sizeof(int));
}
// 填充数据
int count = 1;
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
matrix = count++;
}
}
// 输出矩阵
printf("动态二维数组:\n");
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
printf("%2d ", matrix);
}
printf("\n");
}
// 释放内存
for(int i = 0; i < rows; i++) {
free(matrix);
}
free(matrix);
return0;
}
想要多大的二维数组就创建多大,用完就释放,内存管理变得超灵活! 玩法十五:回调函数——让函数"打电话"这个玩法简直是编程界的社交达人!函数可以调用别的函数:#include <stdio.h>
void sayHello() {
printf("你好!\n");
}
void sayBye() {
printf("再见!\n");
}
void greet(void (*callback)()) {
printf("准备打招呼...\n");
callback(); // 调用传进来的函数
printf("招呼打完了!\n");
}
int main() {
printf("=== 回调函数演示 ===\n");
greet(sayHello);
printf("\n");
greet(sayBye);
return0;
}
看到没?函数也能当参数传来传去,就像打电话一样!玩法十六:链表——指针的终极大招这个是指针的杀手锏应用,数据结构界的明星:#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node *next;// 指向下一个节点的指针
};
void printList(struct Node *head) {
struct Node *current = head;
printf("链表内容:");
while(current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}
int main() {
// 创建三个节点
struct Node *first = (struct Node*)malloc(sizeof(struct Node));
struct Node *second = (struct Node*)malloc(sizeof(struct Node));
struct Node *third = (struct Node*)malloc(sizeof(struct Node));
// 填充数据并连接
first->data = 10;
first->next = second;
second->data = 20;
second->next = third;
third->data = 30;
third->next = NULL;
printList(first); // 输出:10 -> 20 -> 30 -> NULL
// 释放内存
free(first);
free(second);
free(third);
return0;
}
链表就像火车,每节车厢都知道下一节在哪里! 在C语言中,指针是一个非常强大但也容易出错的特性。 未初始化的指针指向未知的内存地址,可能导致不可预测的行为。最好在声明指针时就将其初始化为 NULL 或有效的内存地址。 通过指针传递参数可以修改函数外部的变量。 在使用指针之前,应始终检查它是否为 NULL。 掌握函数指针、宏与指针结合、嵌入式系统中高效使用指针 野指针是指向已释放或未分配内存的指针,使用野指针会导致未定义行为。 在C语言中,指针是强大且灵活的工具,但也是导致程序错误和漏洞的常见原因。 解引用空指针会导致程序崩溃。 在C语言中,指针因其强大的灵活性和直接操作内存的能力
页:
[1]