当前位置: 首页 > news >正文

每日一个C语言知识:C 指针

C语言指针详解

1. 什么是指针?

指针是一个变量,其值是另一个变量的内存地址。简单来说,指针就是存储地址的变量。

指针的核心概念

  • 每个变量都有内存地址
  • 指针存储这些地址
  • 通过指针可以间接访问和修改变量的值

2. 指针的基本概念

C语言指针
基本指针
指针运算
指针与数组
多级指针
函数指针
声明和初始化
解引用
算术运算
关系运算
数组名即指针
指针访问数组
指向指针的指针
回调函数

3. 基本指针操作

指针的声明和使用
#include <stdio.h>int main() {int number = 42;int *ptr;  // 声明一个整型指针printf("=== 基本指针操作 ===\n");// 获取变量的地址ptr = &number;  // & 是取地址运算符printf("变量number的值: %d\n", number);printf("变量number的地址: %p\n", &number);printf("指针ptr的值: %p\n", ptr);printf("指针ptr指向的值: %d\n", *ptr);  // * 是解引用运算符// 通过指针修改变量的值*ptr = 100;printf("通过指针修改后number的值: %d\n", number);// 指针的大小printf("指针ptr的大小: %zu 字节\n", sizeof(ptr));printf("int的大小: %zu 字节\n", sizeof(int));printf("double指针的大小: %zu 字节\n", sizeof(double*));return 0;
}
不同类型的指针
#include <stdio.h>int main() {printf("=== 不同类型的指针 ===\n");int integer = 10;float floating = 3.14;char character = 'A';double double_value = 2.71828;// 声明不同类型的指针int *int_ptr = &integer;float *float_ptr = &floating;char *char_ptr = &character;double *double_ptr = &double_value;printf("整型指针:\n");printf("  值: %d, 地址: %p, 指针值: %p\n", integer, &integer, int_ptr);printf("浮点型指针:\n");printf("  值: %.2f, 地址: %p, 指针值: %p\n", floating, &floating, float_ptr);printf("字符型指针:\n");printf("  值: %c, 地址: %p, 指针值: %p\n", character, &character, char_ptr);printf("双精度指针:\n");printf("  值: %.5f, 地址: %p, 指针值: %p\n", double_value, &double_value, double_ptr);// void指针(通用指针)void *void_ptr = &integer;printf("void指针: %p\n", void_ptr);// printf("*void_ptr = %d\n", *void_ptr);  // ❌ 错误:void指针不能直接解引用return 0;
}
指针的初始化和NULL指针
#include <stdio.h>int main() {printf("=== 指针初始化和NULL指针 ===\n");int x = 50;// 正确的指针初始化方式int *ptr1 = &x;           // 初始化时赋值int *ptr2 = NULL;         // 初始化为NULLint *ptr3;                // 未初始化(危险!)printf("ptr1: %p, 指向的值: %d\n", ptr1, *ptr1);printf("ptr2: %p\n", ptr2);printf("ptr3: %p (未初始化)\n", ptr3);// NULL指针检查if (ptr2 == NULL) {printf("ptr2是NULL指针,不能解引用\n");}// 危险的未初始化指针// printf("*ptr3 = %d\n", *ptr3);  // ❌ 未定义行为!// 安全的指针使用ptr3 = &x;  // 现在ptr3是安全的printf("ptr3现在指向: %p, 值: %d\n", ptr3, *ptr3);return 0;
}

4. 指针运算

指针算术运算
#include <stdio.h>int main() {printf("=== 指针算术运算 ===\n");int numbers[] = {10, 20, 30, 40, 50};int *ptr = numbers;  // 指向数组的第一个元素int size = sizeof(numbers) / sizeof(numbers[0]);printf("数组: ");for (int i = 0; i < size; i++) {printf("%d ", numbers[i]);}printf("\n");printf("指针初始位置: %p, 值: %d\n", ptr, *ptr);// 指针加法ptr = ptr + 1;printf("ptr + 1: %p, 值: %d\n", ptr, *ptr);ptr = ptr + 2;printf("ptr + 2: %p, 值: %d\n", ptr, *ptr);// 指针减法ptr = ptr - 1;printf("ptr - 1: %p, 值: %d\n", ptr, *ptr);// 指针递增递减ptr++;  // 移动到下一个元素printf("ptr++: %p, 值: %d\n", ptr, *ptr);ptr--;  // 移回前一个元素printf("ptr--: %p, 值: %d\n", ptr, *ptr);// 指针差值int *first = &numbers[0];int *last = &numbers[4];printf("第一个和最后一个元素的差值: %ld\n", last - first);return 0;
}
指针关系运算
#include <stdio.h>int main() {printf("=== 指针关系运算 ===\n");int arr[] = {1, 2, 3, 4, 5};int *ptr1 = &arr[1];  // 指向第二个元素int *ptr2 = &arr[3];  // 指向第四个元素printf("arr[1] = %d, 地址: %p\n", arr[1], ptr1);printf("arr[3] = %d, 地址: %p\n", arr[3], ptr2);// 指针比较if (ptr1 < ptr2) {printf("ptr1在ptr2之前\n");}if (ptr1 > ptr2) {printf("ptr1在ptr2之后\n");}if (ptr1 == &arr[1]) {printf("ptr1指向arr[1]\n");}if (ptr1 != ptr2) {printf("ptr1和ptr2指向不同的位置\n");}// 遍历数组使用指针printf("使用指针遍历数组: ");int *current = arr;for (int i = 0; i < 5; i++) {printf("%d ", *current);current++;  // 移动到下一个元素}printf("\n");return 0;
}

5. 指针与数组

数组名即指针
#include <stdio.h>int main() {printf("=== 指针与数组 ===\n");int numbers[] = {10, 20, 30, 40, 50};int size = sizeof(numbers) / sizeof(numbers[0]);printf("数组名numbers: %p\n", numbers);printf("&numbers[0]: %p\n", &numbers[0]);printf("数组名等于第一个元素的地址: %s\n", numbers == &numbers[0] ? "是" : "否");// 不同的访问方式printf("\n=== 数组元素访问方式 ===\n");for (int i = 0; i < size; i++) {printf("numbers[%d] = %d\n", i, numbers[i]);printf("*(numbers + %d) = %d\n", i, *(numbers + i));}// 指针可以像数组一样使用int *ptr = numbers;printf("\n指针像数组一样使用:\n");for (int i = 0; i < size; i++) {printf("ptr[%d] = %d\n", i, ptr[i]);}return 0;
}
指针与多维数组
#include <stdio.h>#define ROWS 3
#define COLS 4int main() {printf("=== 指针与多维数组 ===\n");int matrix[ROWS][COLS] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}};// 使用指针访问二维数组printf("使用指针遍历二维数组:\n");for (int i = 0; i < ROWS; i++) {for (int j = 0; j < COLS; j++) {printf("%d\t", *(*(matrix + i) + j));}printf("\n");}// 数组指针(指向整个一维数组的指针)int (*row_ptr)[COLS] = matrix;printf("\n使用数组指针:\n");for (int i = 0; i < ROWS; i++) {for (int j = 0; j < COLS; j++) {printf("%d\t", row_ptr[i][j]);}printf("\n");}return 0;
}

6. 指针与函数

传值调用 vs 传址调用
#include <stdio.h>// 传值调用 - 接收参数的副本
void swapByValue(int a, int b) {int temp = a;a = b;b = temp;printf("函数内 - a = %d, b = %d\n", a, b);
}// 传址调用 - 接收参数的地址
void swapByReference(int *a, int *b) {int temp = *a;*a = *b;*b = temp;printf("函数内 - *a = %d, *b = %d\n", *a, *b);
}// 返回多个值通过指针参数
void calculate(int a, int b, int *sum, int *product, float *average) {*sum = a + b;*product = a * b;*average = (a + b) / 2.0;
}int main() {printf("=== 指针与函数 ===\n");int x = 5, y = 10;printf("交换前: x = %d, y = %d\n", x, y);// 传值调用swapByValue(x, y);printf("传值调用后: x = %d, y = %d\n", x, y);// 传址调用swapByReference(&x, &y);printf("传址调用后: x = %d, y = %d\n", x, y);// 通过指针返回多个值int sum, product;float average;calculate(x, y, &sum, &product, &average);printf("\n计算结果:\n");printf("和: %d\n", sum);printf("积: %d\n", product);printf("平均值: %.2f\n", average);return 0;
}
数组作为函数参数
#include <stdio.h>// 函数声明
void printArray(int arr[], int size);
void modifyArray(int *arr, int size);
int* findMax(int arr[], int size);int main() {int numbers[] = {23, 45, 12, 67, 34, 89, 56};int size = sizeof(numbers) / sizeof(numbers[0]);printf("=== 数组作为函数参数 ===\n");printf("原始数组: ");printArray(numbers, size);// 修改数组modifyArray(numbers, size);printf("修改后数组: ");printArray(numbers, size);// 返回指针的函数int *max_ptr = findMax(numbers, size);printf("最大值: %d (地址: %p)\n", *max_ptr, max_ptr);return 0;
}// 使用数组语法
void printArray(int arr[], int size) {for (int i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}// 使用指针语法(两种语法是等价的)
void modifyArray(int *arr, int size) {for (int i = 0; i < size; i++) {arr[i] *= 2;  // 等价于 *(arr + i) *= 2}
}// 返回指针的函数
int* findMax(int arr[], int size) {int *max_ptr = &arr[0];for (int i = 1; i < size; i++) {if (arr[i] > *max_ptr) {max_ptr = &arr[i];}}return max_ptr;
}

7. 多级指针

二级指针
#include <stdio.h>int main() {printf("=== 多级指针 ===\n");int value = 100;int *ptr = &value;     // 一级指针int **pptr = &ptr;     // 二级指针int ***ppptr = &pptr;  // 三级指针printf("变量value: %d\n", value);printf("变量value的地址: %p\n", &value);printf("一级指针ptr: %p\n", ptr);printf("ptr指向的值: %d\n", *ptr);printf("ptr的地址: %p\n", &ptr);printf("二级指针pptr: %p\n", pptr);printf("pptr指向的值(ptr的地址): %p\n", *pptr);printf("pptr指向的指针指向的值: %d\n", **pptr);printf("三级指针ppptr: %p\n", ppptr);printf("ppptr指向的指针指向的指针指向的值: %d\n", ***ppptr);// 通过多级指针修改变量值**pptr = 200;printf("通过二级指针修改后value的值: %d\n", value);***ppptr = 300;printf("通过三级指针修改后value的值: %d\n", value);return 0;
}
指针数组
#include <stdio.h>int main() {printf("=== 指针数组 ===\n");int a = 10, b = 20, c = 30, d = 40;// 指针数组 - 存储指针的数组int *ptr_array[4] = {&a, &b, &c, &d};printf("指针数组内容:\n");for (int i = 0; i < 4; i++) {printf("ptr_array[%d] = %p, *ptr_array[%d] = %d\n", i, ptr_array[i], i, *ptr_array[i]);}// 修改通过指针数组*ptr_array[0] = 100;*ptr_array[1] = 200;printf("\n修改后:\n");printf("a = %d, b = %d\n", a, b);return 0;
}

8. 动态内存分配

malloc, calloc, realloc, free
#include <stdio.h>
#include <stdlib.h>int main() {printf("=== 动态内存分配 ===\n");int *dynamic_array;int size;printf("请输入数组大小: ");scanf("%d", &size);if (size <= 0) {printf("错误:大小必须为正数!\n");return 1;}// 使用malloc分配内存(不初始化)dynamic_array = (int*)malloc(size * sizeof(int));if (dynamic_array == NULL) {printf("内存分配失败!\n");return 1;}printf("使用malloc分配的内存(未初始化):\n");for (int i = 0; i < size; i++) {printf("%d ", dynamic_array[i]);  // 可能包含垃圾值}printf("\n");// 初始化数组for (int i = 0; i < size; i++) {dynamic_array[i] = i * 10;}printf("初始化后的数组:\n");for (int i = 0; i < size; i++) {printf("%d ", dynamic_array[i]);}printf("\n");// 使用calloc分配内存(初始化为0)int *another_array = (int*)calloc(size, sizeof(int));printf("使用calloc分配的内存(初始化为0):\n");for (int i = 0; i < size; i++) {printf("%d ", another_array[i]);}printf("\n");// 使用realloc调整内存大小int new_size = size * 2;dynamic_array = (int*)realloc(dynamic_array, new_size * sizeof(int));// 初始化新分配的部分for (int i = size; i < new_size; i++) {dynamic_array[i] = i * 10;}printf("realloc后的数组:\n");for (int i = 0; i < new_size; i++) {printf("%d ", dynamic_array[i]);}printf("\n");// 释放内存free(dynamic_array);free(another_array);printf("内存已释放\n");return 0;
}
动态二维数组
#include <stdio.h>
#include <stdlib.h>int main() {printf("=== 动态二维数组 ===\n");int rows, cols;printf("请输入行数: ");scanf("%d", &rows);printf("请输入列数: ");scanf("%d", &cols);// 分配行指针数组int **matrix = (int**)malloc(rows * sizeof(int*));if (matrix == NULL) {printf("内存分配失败!\n");return 1;}// 为每一行分配内存for (int i = 0; i < rows; i++) {matrix[i] = (int*)malloc(cols * sizeof(int));if (matrix[i] == NULL) {printf("内存分配失败!\n");return 1;}}// 初始化矩阵for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {matrix[i][j] = i * cols + j + 1;}}// 打印矩阵printf("动态二维数组:\n");for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {printf("%d\t", matrix[i][j]);}printf("\n");}// 释放内存(按分配的顺序反向释放)for (int i = 0; i < rows; i++) {free(matrix[i]);}free(matrix);printf("内存已释放\n");return 0;
}

9. 函数指针

基本函数指针
#include <stdio.h>// 简单的数学运算函数
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
int divide(int a, int b) { if (b != 0) return a / b; return 0;
}// 使用函数指针作为参数
void calculate(int a, int b, int (*operation)(int, int)) {int result = operation(a, b);printf("计算结果: %d\n", result);
}int main() {printf("=== 函数指针 ===\n");// 声明函数指针int (*func_ptr)(int, int);int x = 10, y = 5;// 使用函数指针调用不同的函数func_ptr = add;printf("加法: ");calculate(x, y, func_ptr);func_ptr = subtract;printf("减法: ");calculate(x, y, func_ptr);func_ptr = multiply;printf("乘法: ");calculate(x, y, func_ptr);func_ptr = divide;printf("除法: ");calculate(x, y, func_ptr);// 函数指针数组int (*operations[])(int, int) = {add, subtract, multiply, divide};const char* operation_names[] = {"加法", "减法", "乘法", "除法"};printf("\n使用函数指针数组:\n");for (int i = 0; i < 4; i++) {printf("%s: %d\n", operation_names[i], operations[i](x, y));}return 0;
}
回调函数
#include <stdio.h>// 回调函数类型定义
typedef int (*CompareFunc)(int, int);// 比较函数
int ascending(int a, int b) { return a - b; }
int descending(int a, int b) { return b - a; }// 使用回调函数的排序函数
void bubbleSort(int arr[], int size, CompareFunc compare) {for (int i = 0; i < size - 1; i++) {for (int j = 0; j < size - i - 1; j++) {if (compare(arr[j], arr[j + 1]) > 0) {// 交换int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}void printArray(int arr[], int size) {for (int i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}int main() {printf("=== 回调函数示例 ===\n");int numbers[] = {64, 34, 25, 12, 22, 11, 90};int size = sizeof(numbers) / sizeof(numbers[0]);printf("原始数组: ");printArray(numbers, size);// 升序排序bubbleSort(numbers, size, ascending);printf("升序排序: ");printArray(numbers, size);// 降序排序bubbleSort(numbers, size, descending);printf("降序排序: ");printArray(numbers, size);return 0;
}

10. 实际应用示例

示例1:字符串处理工具
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 自定义字符串函数
char* myStrcpy(char *dest, const char *src);
char* myStrcat(char *dest, const char *src);
int myStrcmp(const char *str1, const char *str2);
char* myStrrev(char *str);int main() {printf("=== 字符串处理工具 ===\n");// 动态分配字符串char *str1 = (char*)malloc(100 * sizeof(char));char *str2 = (char*)malloc(100 * sizeof(char));if (str1 == NULL || str2 == NULL) {printf("内存分配失败!\n");return 1;}// 测试自定义字符串函数myStrcpy(str1, "Hello");myStrcpy(str2, "World");printf("str1: %s\n", str1);printf("str2: %s\n", str2);printf("比较结果: %d\n", myStrcmp(str1, str2));myStrcat(str1, " ");myStrcat(str1, str2);printf("连接后: %s\n", str1);myStrrev(str1);printf("反转后: %s\n", str1);// 释放内存free(str1);free(str2);return 0;
}// 自定义字符串复制
char* myStrcpy(char *dest, const char *src) {char *start = dest;while (*src != '\0') {*dest = *src;dest++;src++;}*dest = '\0';return start;
}// 自定义字符串连接
char* myStrcat(char *dest, const char *src) {char *start = dest;// 找到dest的结尾while (*dest != '\0') {dest++;}// 复制src到dest的结尾while (*src != '\0') {*dest = *src;dest++;src++;}*dest = '\0';return start;
}// 自定义字符串比较
int myStrcmp(const char *str1, const char *str2) {while (*str1 && *str2 && *str1 == *str2) {str1++;str2++;}return *str1 - *str2;
}// 自定义字符串反转
char* myStrrev(char *str) {if (str == NULL) return NULL;char *start = str;char *end = str;char temp;// 找到字符串结尾while (*end != '\0') {end++;}end--;  // 指向最后一个字符// 反转字符串while (start < end) {temp = *start;*start = *end;*end = temp;start++;end--;}return str;
}
示例2:学生管理系统
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MAX_NAME_LENGTH 50typedef struct {char name[MAX_NAME_LENGTH];int age;float score;
} Student;// 函数声明
Student* createStudent(const char *name, int age, float score);
void displayStudent(const Student *student);
void updateStudentScore(Student *student, float new_score);
void freeStudent(Student *student);int main() {printf("=== 学生管理系统 ===\n");// 动态创建学生Student *student1 = createStudent("张三", 20, 85.5);Student *student2 = createStudent("李四", 22, 92.0);Student *student3 = createStudent("王五", 21, 78.5);if (student1 == NULL || student2 == NULL || student3 == NULL) {printf("学生创建失败!\n");return 1;}// 显示学生信息printf("=== 学生信息 ===\n");displayStudent(student1);displayStudent(student2);displayStudent(student3);// 更新成绩printf("\n=== 更新成绩 ===\n");updateStudentScore(student3, 88.0);displayStudent(student3);// 学生数组Student *students[] = {student1, student2, student3};int student_count = 3;// 计算平均分float total_score = 0;for (int i = 0; i < student_count; i++) {total_score += students[i]->score;}printf("\n平均分: %.2f\n", total_score / student_count);// 释放内存for (int i = 0; i < student_count; i++) {freeStudent(students[i]);}printf("内存已释放\n");return 0;
}// 创建学生
Student* createStudent(const char *name, int age, float score) {Student *student = (Student*)malloc(sizeof(Student));if (student == NULL) {return NULL;}strncpy(student->name, name, MAX_NAME_LENGTH - 1);student->name[MAX_NAME_LENGTH - 1] = '\0';student->age = age;student->score = score;return student;
}// 显示学生信息
void displayStudent(const Student *student) {printf("姓名: %s, 年龄: %d, 分数: %.1f\n", student->name, student->age, student->score);
}// 更新学生成绩
void updateStudentScore(Student *student, float new_score) {student->score = new_score;printf("%s的成绩已更新为: %.1f\n", student->name, new_score);
}// 释放学生内存
void freeStudent(Student *student) {free(student);
}

11. 常见指针错误

#include <stdio.h>
#include <stdlib.h>int main() {printf("=== 常见指针错误 ===\n");// ❌ 错误1:使用未初始化的指针/*int *ptr;printf("%d\n", *ptr);  // 未定义行为*/// ✅ 正确:总是初始化指针int x = 10;int *ptr = &x;printf("正确使用: %d\n", *ptr);// ❌ 错误2:访问已释放的内存/*int *dynamic_ptr = (int*)malloc(sizeof(int));*dynamic_ptr = 100;free(dynamic_ptr);printf("%d\n", *dynamic_ptr);  // 错误:访问已释放的内存*/// ✅ 正确:释放后设为NULLint *dynamic_ptr = (int*)malloc(sizeof(int));*dynamic_ptr = 100;free(dynamic_ptr);dynamic_ptr = NULL;  // 防止悬空指针// ❌ 错误3:内存泄漏/*void leakMemory() {int *ptr = (int*)malloc(100 * sizeof(int));// 忘记free(ptr)}*/// ✅ 正确:配对使用malloc/freeint *safe_ptr = (int*)malloc(sizeof(int));if (safe_ptr != NULL) {*safe_ptr = 50;printf("安全使用: %d\n", *safe_ptr);free(safe_ptr);}// ❌ 错误4:返回局部变量的地址/*int* dangerousFunction() {int local_var = 100;return &local_var;  // 错误:返回局部变量的地址}*/// ✅ 正确:返回动态分配的内存或静态变量int* safeFunction() {static int static_var = 200;  // 静态变量return &static_var;}int *result = safeFunction();printf("安全返回: %d\n", *result);return 0;
}

http://www.dtcms.com/a/497052.html

相关文章:

  • 详解窗口函数中的RANGE BETWEEN子句
  • 30、Linux 磁盘基本原理、管理
  • ps如何做网站首页阿里 wordpress 安装
  • 淘宝客聚惠购的网站怎么做网站浏览历史怎么查看
  • Python 常用模块
  • 卫星授时原理
  • 2025时空低空经济发展现状与智能化趋势
  • 哪个网站推广做的好做网站素材在哪找
  • 荆州公司做网站多仓库版仓库管理网站建设源码
  • 哈尔滨餐饮网站建设外包公司的人好跳槽吗
  • 高中课程免费教学网站网络规划设计师知识点
  • 企业官方网站制作wordpress 3.8.1 exp 下载
  • 为什么做腾讯网站网站建设方案与报价
  • 网站建设教程特别棒湖南岚鸿权 威工业设计专业最好的大学世界排名
  • 2 网站内部链接优化网址大全
  • 3D Gaussian Splatting论文简要解读与可视化复现(基于gsplat)
  • 养老网站备案必须做前置审批吗天津电商网站建设
  • Spring Data Redis
  • 站长之家工具高清网站的百度推广怎么做
  • 深圳微信网站运营免费网站建站系统
  • 沈阳网站建设的公司西安网站推广排名
  • 购物网站有哪些平台百度网盘搜索引擎
  • 火币网(Huobi Pro)是否正规?是否存在安全漏洞?——深度解析
  • 第3章,[标签 Win32] :窗口类03,窗口过程函数字段
  • 软件开发网站开发公司工作组赴平凉事故现场
  • 友情链接如何选择网站工程招标信息网
  • 现在建设的网站有什么劣势网站建设公司盈利分析
  • 广西网站设计服务代码优化网站排名
  • django 网站开发视频杭州品牌网站建设
  • 白银市建设局网站首页包头微网站开发