C语言——第四章指针
引言
C语言的一些基本例题
全部例题来自于C语言王道训练营 链接如下
B站链接.
书籍:《跟“龙哥”学C语言编程》
1.引用与解引用
下面展示一些 可运行的代码
。
#include<stdio.h>
#include<stdlib.h>
int main()
{
int i = 10;
int j = 5;
int* p;//指针变量用来存储地址
p = &i;
printf("i=%d\n", i);//直接引用
printf("p=%d\n", *p);//间接引用
printf("%p\n", &*p);//&* pointer_1与&a相同,都表示变量a的地址
printf("%d\n", *&i);//*&a与a等价
system("pause");
return 0;
}
运行结果
i=10
p=10
0032F728
10
请按任意键继续. . .
2.指针的传递
下面展示一些 可运行的代码
。
#include<stdio.h>
#include<stdlib.h>
void change(int j)
{
j = 5;
}
void zzchange(int* p)
{
*p = 5;//间接访问得到变量i
}
int main()
{
int i = 10;
printf("before change i=%d\n", i);
change(i);//当我们在change函数的函数栈空间内修改变量j的值后,change函数执行结束,其栈空间就会释放,j就不再存在,i的值不会改变。
printf("after change i=%d\n", i);
zzchange(&i);//传递i的地址
printf("after zzchange i=%d\n", i);
system("pause");
return 0;
}
运行结果
before change i=10
after change i=10
after zzchange i=5
请按任意键继续. . .
3.指针的偏移
下面展示一些 可运行的代码
。
#include<stdio.h>
#include<stdlib.h>
#define N 5
int main()
{
int a[N] = { 1,2,3,4,5 };
int* p;
int i;
p = a;//保证符号两边的数值类型一致
for (i = 0; i < N; i++)//正序输出
{
printf("%3d", *(p + i));
}
printf("\n----------------------------\n");
p = &a[4];//p指向最后一个元素
for (i = 0; i < N; i++)//逆序输出
{
printf("%-3d", *(p - i));
}
printf("\n");
system("pause");
return 0;
}
运行结果
1 2 3 4 5
----------------------------
5 4 3 2 1
请按任意键继续. . .
4.指针与自增、自减
下面展示一些 可运行的代码
。
#include<stdio.h>
#include<stdlib.h>
//只有比后增优先级高的操作符,才会作为一个整体,如(),[]
int main()
{
int a[3] = { 2,7,10 };
int* p;
int j;
p = a;
j = *p++;//j=*p,p++:p向后偏移
printf("a[0]=%d,j=%d,*p=%d\n", a[0], j, *p);
j = p[0]++;//j=p[0],p[0]++:p[0]的值+1
printf("a[0]=%d,j=%d,*p=%d\n", a[0], j, *p);
system("pause");
return 0;
}
运行结果
a[0]=2,j=2,*p=7
a[0]=2,j=7,*p=8
请按任意键继续. . .
5.指针与一维数组
下面展示一些 可运行的代码
。
#include<stdio.h>
#include<stdlib.h>
void change(char *d)
{
*d = 'H';
d[1] = 'E';
*(d + 2) = 'L';
}
int main()
{
char c[10] = "hello";//等价于strcpy(c,"hello)
char* p = "world";//把字符串常量'world'的首地址赋给p
change(c);//c为实参
printf("c=%s\n", c);
printf("p=%s\n", p);
//p[0]='H';//不可以对常量区数据进行修改
p = "hello";//将字符串'hello'地址赋给p
printf("p=%s\n", p);
//c='world';//非法
system("pause");
return 0;
}
运行结果
c=HELlo
p=world
p=hello
请按任意键继续. . .
6.动态内存申请
下面展示一些 可运行的代码
。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int i;
char* p;
scanf("%d", &i);//输入申请的空间大小
p = (char *)malloc(i);//使用malloc动态申请空间,并返回空间的首地址
strcpy(p, "malloc success");
puts(p);
free(p);//free时必须使用malloc申请时返回的指针值,不能进行任何偏移
printf("free success\n");
system("pause");
return 0;
}
运行结果
20
malloc success
free success
请按任意键继续. . .
7.野指针
下面展示一些 可运行的代码
。
#include<stdio.h>
#include<stdlib.h>
//在free(p)之后,需要把p置为NULL,也就是在free(p)之后加上p=NULL。如果不置为NULL,那么这时的p称为野指针。
//malloc函数内部的内存管理算法把free(p1)刚刚释放的空间分配给了p3,因此p1这时和p3指向同一块内存空间。
int main()
{
int* p1, * p2, * p3;
p1 = (int*)malloc(4);
*p1 = 1;
p2 = (int*)malloc(4);
*p2 = 2;
free(p1);//释放原为p1申请的空间,但未将p1赋值为NULL
p3 = (int*)malloc(4);
*p3 = 3;
printf("*p3=%d\n", *p3);
*p1 = 100;
printf("*p1赋值100后,*p3=%d\n", *p3);
system("pause");
return 0;
}
运行结果
*p3=3
*p1赋值100后,*p3=100
请按任意键继续. . .
8.栈空间与堆空间的差异
下面展示一些 可运行的代码
。
#include<stdio.h>
#include<stdlib.h>
//函数栈空间释放后,函数内的所有局部变量消失
char* print_stack()
{
char c[] = "I am print_stack";
puts(c);
return c;
}
//堆空间不会因为函数执行结束而释放
//堆空间只有在执行free操作后才会释放,否则在进程执行过程中会一直有效
char* print_malloc()
{
char* p;
p = (char*)malloc(20);
strcpy(p, "I am print_malloc");
puts(p);
return p;
}
int main()
{
char* p;
p = print_stack(); //数据存放在栈空间
puts(p);
p = print_malloc();
puts(p);
system("pause");
return 0;
}
运行结果
I am print_stack
H`?
I am print_malloc
I am print_malloc
请按任意键继续. . .
9.深入理解const
下面展示一些 可运行的代码
。
#include<stdio.h>
#include<stdlib.h>
int main()
{
char str[] = "hello world";
char str1[] = "how do you do";
//ptr是一个指向char*类型的常量,不能用ptr来修改所指向的内容
const char* ptr = str;
//const指针,不能修改ptr1指针,但可以修改该指针指向的内容。
char* const ptr1 = str1;
str[0] = 'H';//操作合法
printf("++++str的内容++++\n");
puts(str);
printf("++++str1的内容++++\n");
puts(str1);
printf("++++ptr1指向str1++++\n");
puts(ptr1);
ptr1[0] = 'n';//合法
printf("++++ptr1修改后++++\n");
puts(ptr1);
//不能通过ptr指针来修改
//ptr[0] = 'n';//操作非法,编译错误,错误E0137:表达式必须是可修改的左值
printf("++++ptr指向str++++\n");
puts(ptr);
ptr = str1;
printf("++++ptr更改指向str1++++\n");
puts(ptr);
//ptr1 = str;//非法,编译错误,左值指定const对象
system("pause");
}
运行结果
++++str的内容++++
Hello world
++++str1的内容++++
how do you do
++++ptr1指向str1++++
how do you do
++++ptr1修改后++++
now do you do
++++ptr指向str++++
Hello world
++++ptr更改指向str1++++
now do you do
请按任意键继续. . .
10.memmove的实现
下面展示一些 可运行的代码
。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 5
int main()
{
int a[N] = { 1,2,3,4,5 };
int b[N] = { 1,2,3,4,5 };
int i;
memmove(b + 2, b + 1, 8);//将3 4 用2 3代替
for (i = 0; i < N; i++)
{
printf("%3d", b[i]);
}
printf("\n");
system("pause");
return 0;
}
运行结果
1 2 2 3 5
请按任意键继续. . .
11.数组指针与二维数组
下面展示一些 可运行的代码
。
#include<stdio.h>
#include<stdlib.h>
void print(int (*p)[4], int row)
{
//int p[][4]改为int (*p)[4],二者是等价的
//对于打印位置的p[i][j],可以写成*(*(p+i)+j),一般来说,我们更多地使用形式p[i][j]
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < sizeof(p[0]) / sizeof(int); j++)
{
printf("%-3d",*(*(p+i)+j));
}
printf("\n");
}
}
//数组指针用于二维数组的传递和偏移
int main()
{
int a[3][4] = { 1,3,5,7,9,11,13,15,17,19,21,23 };
int b[4] = { 1,2,3,4 };
int i = 10;
int(*p)[4];//定义一个数组指针
p = a;
print(a, 3);
system("pause");
return 0;
}
运行结果
1 3 5 7
9 11 13 15
17 19 21 23
请按任意键继续. . .
12.二级指针的传递
下面展示一些 可运行的代码
。
#include<stdio.h>
#include<stdlib.h>
//二级指针也是一种指针,其作用也是传递和偏移
//二级指针只服务于一级指针的传递与偏移
void change(int** p, int* pj)
{
*pj= 15;
*p = pj;
}
//要想在子函数中改变一个变量的值,必须把该变量的地址传进去
//要想在子函数中改变一个指针变量的值,必须把该指针变量的地址传进去
int main()
{
int i = 10;
int j = 5;
int* pi, * pj;
pi = &i;
pj = &j;
printf("i=%d,*pi=%d,*pj=%d\n", i, *pi, *pj);
change(&pi, pj);
printf("after change i=%d,*pi=%d,*pj=%d\n", i, *pi, *pj);
system("pause");
return 0;
}
运行结果
i=10,*pi=10,*pj=5
after change i=10,*pi=15,*pj=15
请按任意键继续. . .
13.二级指针的偏移
下面展示一些 可运行的代码
。
#include<stdio.h>
#include<stdlib.h>
void print(char* p[])//这里可以写成char **p
{
int i;
for (i = 0; i < 5; i++)
{
puts(p[i]);
}
}
//二级指针的偏移,服务的时指针数组
int main()
{
char* p[5];//定义一个指针数组
char b[5][10] = { "lele","lili","lilei","hanmeimei","zhousi" };
int i, j, tmp;
char* t;
char** p2;
int a[5] = { 3,7,9,2,4 };
for (i = 0; i < 5; i++)
{
p[i] = b[i];//让指针数组中的每个指针都指向一个字符串
}
p2 = p;
for (i = 4; i > 0; i--)
{
for (j = 0; j < i; j++)
{
if (strcmp(p2[j], p2[j + 1]) == 1) //判断p2[j]是否大于p2[j+1]
{
t = p2[j];
p2[j] = p2[j + 1];
p2[j + 1] = t;
}
}
}
print(p2);
puts("----------------");
for (i = 0; i < 5; i++)
{
puts(b[i]);
}
system("pause");
return 0;
}
运行结果
hanmeimei
lele
lilei
lili
zhousi
----------------
lele
lili
lilei
hanmeimei
zhousi
请按任意键继续. . .
14.函数指针
下面展示一些 可运行的代码
。
#include<stdio.h>
#include<stdlib.h>
void b()
{
printf("I am func b\n");
}
void a(void (*p)())
{
p();
}
//定义函数指针,初始化只能赋函数名
int main()
{
void (*p)();//定义一个函数指针变量
p = b;
a(p);
system("pause");
return 0;
}
运行结果
I am func b
请按任意键继续. . .
总结
第一次发表一篇完整的博客,对于一些遗漏,读者不要太过深究~
比较适合新手打基础大佬请绕路~
希望这些可以帮助你更好的理解C语言
马上就考研了 我居然还在纠结一些基础 真是闲的闲的闲的闲*10000!
过几天在更新后几章的内容
欢迎大家评论、收藏、点赞 !!!