1 你是否渴望在短时间内彻底攻克 C 语言指针这一重难点?
本人耗时 5 天,手敲 600 行代码,精心整理了全部 C 语言数组与指针的常见考点及面试重难点。通过多个精心设计的实验,涵盖数组元素访问、多维数组转置、动态内存分配、字符串操作、函数指针、链表操作、排序算法、结构体嵌套等内容,深度剖析指针在 C 语言中的应用
每个实验都包含:
-
1底层原理剖析:揭秘指针与数组的本质关联
-
2调试技巧:教你在GDB中追踪内存泄漏
-
3性能优化:掌握位运算在嵌入式开发中的实战应用
-
4面试高频考点:覆盖腾讯T3/4、字节跳动SP级别的真题解析
2 上代码!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
// 指针访问数组中的元素
void arr1_ptr()
{
int arr[] = {1, 2, 4, 5, 6, 56, 67, 8, 9};
int *ptr = arr;
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; i++)
{
printf("指针访问:%d,数组访问:%d\n ", *(ptr + i), arr[i]);
}
}
// 转置操作
// #self 数组没办法获取数组大小 :sizeof(arr)这个会失效!!!
void zhuanzhi(int arr[3][3])
{
for (int i = 0; i < 3; i++)
{
for (int j = i + 1; j < 3; j++)
{
int temp = arr[i][j];
arr[i][j] = arr[j][i];
arr[j][i] = temp;
}
}
}
static void dy_alloc_mem()
{
int *arr1 = (int *)malloc(1000000 * sizeof(int));
if (arr1 == NULL)
{
printf("内存分配失败!\n");
return;
}
for (int i = 0; i < 1000000; i++)
{
*(arr1 + i) = i;
}
// 时间戳1
clock_t start, end;
start = clock();
int i;
for (i = 0; i < 100; i++)
{
printf("%d \n", *(arr1 + i));
}
end = clock();
double t = (double)(end - start);
printf("打印这些%d用了%10f毫秒\n", i, t);
//
// 时间戳2
}
void string_reverse(char *str, int len)
{
char *start = str;
char *end = start + len - 1;
while (start < end)
{
char temp = *start;
*start = *end;
*end = temp;
start++;
end--;
}
}
int add(int a, int b)
{
return a + b;
}
int substract(int a, int b)
{
return a - b;
}
struct Person
{
char name[10];
int age;
};
struct Node
{
int data;
struct Node *next;
};
struct Node *insert_atFirst(struct Node *head, int data)
{
// self
// vip!!!
// 在末尾插入!
struct Node *n_node = (struct Node *)malloc(sizeof(struct Node));
n_node->data = data;
n_node->next = head;
return n_node;
}
void print_List(struct Node *node)
{
struct Node *l = node;
while (l != NULL)
{
printf("这是打印的节点:!!! %d \n", l->data);
l = l->next;
}
return;
}
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int cnt11 = 0;
int partition(int arr[], int low, int high)
{
int pi = arr[high];
int i = low - 1;
for (int j = low; j <= high - 1; j++)
{
if (arr[j] <= pi)
{
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
printf("\n\n---现在是partition%d次调用\n,pi是%d\n", cnt11++, pi);
for (int i = 0; i < high; i++)
{
printf(" %d-", arr[i]);
}
printf("---现在是partition%d次调用\n\n", cnt11++);
return i + 1;
}
void quick_Sort(int arr[], int low, int high)
{
if (low < high)
{
int pi = partition(arr, low, high);
quick_Sort(arr, low, pi - 1);
quick_Sort(arr, pi + 1, high);
}
}
struct Address{
char street[50];
int house_number;
};
struct Person_16{
char name[20];
struct Address address;
};
void Print_address(struct Person_16* p){
printf("%s \n",p->name);
printf("%s \n",p->address.street);
printf("%d \n",p->address.house_number);
}
//#self vip !!!!
//不自己写 根本就不知道有这么多不懂的内容!
void connect_char(char* a,char* b){
char* p1 = a + strlen(a);
printf("这是实验18里面的callback,a的长度是:%d ,b的长度是:%d\n",strlen(a),strlen(b));
// for(int i=0;i<strlen(b);i++){
// a[i] = b[i];
// }
while(*b!='\0'){
*p1 = *b;
p1++;b++;
}
*p1 = '\0';
}
#define maxL 100
struct stack{
int data[maxL] ;
int top ;
};
void initStack(struct stack* s ){
s->top=-1;
}
int isEmpty(struct stack* s ){
if(s->top==-1){
return 1;
}
else{
return -100;
}
}
int isFull(struct stack* s ){
if(s->top==maxL){
return 1;
}
else{
return 0;
}
}
void pushStack(struct stack* s ,int data ){
//判断栈是不是满了?
if(s->top==maxL){
return ;
}
else{
s->data[++(s->top)] = data;
}
}
int popStack(struct stack* s ){
//判断是不是空?空了就返回-1
if(isEmpty(s)){
return -1;
}
else{
int res = s->data[s->top--];
}
}
int peekTop(struct stack* s ){
return s->data[s->top];
}
int main()
{
// 访问数组元素
// arr1_ptr();
// printf("1 访问数组元素结束!\n");
// // 多维数组的内存布局
// // 把一个二维数组转置操作一下
// // #self 数组没办法获取数组大小 :sizeof(arr)这个会失效!!!
// int arr[3][3] = {
// {1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
// zhuanzhi(arr);
// for (int i = 0; i < 3; i++)
// {
// for (int j = 0; j < 3; j++)
// {
// printf("%d ", arr[i][j]);
// }
// printf("\n");
// }
// printf("\n\n实验转置操作\n");
// // 动态分配内存打印
// printf("第3实验开始!\n");
// dy_alloc_mem();
// printf("第3实验结束!\n");
// printf("\n\n第四个实验开始\n\n");
// char charS[100] = {'0', '1', '2', '3', '4', '5', '\0'};
// int char_len = strlen(charS);
// printf("这个字符数组的长度:%d \n", char_len);
// printf("但是强行从0-100打印就是:\n");
// for (int i = 0; i < 5; i++)
// {
// printf("%c \n", charS[i]);
// }
// string_reverse(charS, char_len);
// for (int i = 0; i < char_len; i++)
// {
// printf("%c \n", charS[i]);
// }
// printf("第4个实验结束\n\n");
// // 第5个实验:函数指针
// // 手动实现一个计算器
// printf("\n第5个实验开始\n\n");
// int a = 100, b = 50;
// int (*func_ptr)(int a, int b);
// printf("告诉我你要的操作:\n");
// char op;
// scanf("%c", &op);
// switch (op)
// {
// case '+':
// func_ptr = add;
// {
// int res = func_ptr(a, b);
// printf("%d\n", res);
// break;
// }
// case '-':
// func_ptr = substract;
// {
// int res = func_ptr(a, b);
// printf("%d\n", res);
// break;
// }
// }
// printf("\n第5个实验结束\n\n");
// printf("\n第六个实验,二维数组动态分配\n");
// int m =3,n =4 ;
// int **arr_6 =(int**)malloc(m*sizeof(int*));
// for(int i= 0;i<m;i++){
// arr_6[i] = (int*)malloc(n*sizeof(int));
// }
// for(int i =0;i<m;i++){
// for(int j =0;j<n;j++){
// arr_6[i][j] = i*n+j;
// printf("\n%d = %d 行 %d列",arr_6[i][j],i,j);
// }
// printf("\n");
// }
// printf("\n第六个实验,二维数组动态分配\n");
printf("实验7 指针数组用法\n");
char *string[] = {"jibamao", "abc", "123", "why", "你是神秘嘉宾", "\0"};
int len7 = sizeof(string) / sizeof(string[0]);
for (int i = 0; i < len7; i++)
{
printf("%s\n", string[i]);
}
char string7[] = "123123";
printf("%d\n", sizeof(string7));
for (int i = 0; i < sizeof(string7); i++)
{
printf("%c", string7[i]);
}
// #self vip
// 特别重要 字符串数组和字符指针数组
// 结构体指针8 实验8 结构体修改结构体内值
//
struct Person person = {"xiaomin", 18};
printf("\n%s-%d\n", person.name, person.age);
struct Person *p = &person;
strcpy(p->name, "jibamao");
// p->name = "jibamao";
printf("改过之后:%s\n", p->name);
// #self vip!
// 结构体指针的作用
// #self
// 实验9 链表节点的插入
printf("\n\n实验9 链表的插入\n");
struct Node *head_node = NULL;
// struct Node node = {123,NULL};
head_node = insert_atFirst(head_node, 123);
printf("\n第一个节点:%d\n ", head_node->data);
head_node = insert_atFirst(head_node, 4);
printf("\n第二个节点 : %d\n", head_node->data);
print_List(head_node);
// #self vip!!!
// 实验10 冒泡排序优化
printf("实验10 冒泡排序优化!\n");
// 11 快排法
// #self vip!!!
printf("\n\n实验11 快速排序!!开始!!!\n");
int arr11[] = {4, 5, 6, 7, 15, 234, 46, 698, 238, 258, 45, 2, 36, 26, 123, 77, 5, 48, 45, 2, 5, 325, 32, 1, 6};
int len = sizeof(arr11) / sizeof(arr11[0]);
quick_Sort(arr11, 0, len - 1);
for (int i = 0; i < len; i++)
{
printf("快排打印的结果是");
printf("%d\n", arr11[i]);
}
printf("\n\n实验11 快排结束!!!\n");
// 13实验 文件读写操作
//
// 14整数阶乘
// 15指针数组与二维数组区别:
// #self vip
printf("\n\n实验15开始 \n\n");
char *str15[] = {"ab", "123", "efg", "jkl"};
char str15new[3][10] = {"baname", "apple", "milk"};
int len1 = sizeof(strlen(str15))/sizeof(str15[0]);
for (int i = 0; i <len1; i++)
{
printf("%s \n", str15[i]);
}
printf("\n\n");
for (int i = 0; i < strlen(str15new); i++)
{
printf("%s \n", str15new[i]);
}
//实验16 结构体嵌套
printf("\n\n实验16开始 \n\n");
struct Person_16 p16 = {"xiaom",{"123abc",100}};
Print_address(&p16);
printf("\n\n实验16结束 \n\n");
//实验17 位运算实现假发
//shyan 18 指针实现字符串拼接
//告诉两个指针的地址,直接把连个地址相加即可
printf("\n\n实验18开始 ---------\n\n");
char char1 []= {'1','2','3','4','5','a','\0'};
char char2 []= {'b','9','\0'};
connect_char(char1,char2);
int len18 = strlen(char1);
printf("\n18实验的长度是:%d \n\n",len18);
for(int i =0;i<len18;i++){
printf("%c \n",char1[i]);
}
printf("\n\n实验18结束 ---------------\n\n");
//实验19
//later
//检测是否链表有环形结构
//实验20
//自己实现一个栈结构
//#self vip!!!
//栈要实现哪些功能?
//1 初始化 2入栈 3出栈 4查看栈顶元素 5空了? 6满了?
struct stack s;
initStack(&s);
printf("初始了,是不是空?%d\n",isEmpty(&s));
pushStack(&s,1);
printf("插入了1,是不是空?\n",isEmpty(&s));
pushStack(&s,2);
pushStack(&s,3);
printf("栈顶是:%d\n",peekTop(&s));
pushStack(&s,4);
printf("栈顶是:%d\n",peekTop(&s));
popStack(&s);
printf("栈顶是:%d\n",peekTop(&s));
printf("栈顶是:%d\n",peekTop(&s));
return 0;
}
3 写给正在攀登技术高峰的你
“当初我学void (*signal(int sig, void (*handler)(int)))(int);
时,整整3天没看懂。后来在深圳凌晨3点的出租屋里,当我突然顿悟函数指针声明的语法时,那种颅内高潮般的快感,至今难忘。”
特别提示:文末提供完整源码包(含调试注释),前100名私信者可获取《C语言指针进阶手册》PDF版。技术的道路上,我们永远在互相成就!