指针介绍
指针:就是内存地址 定义指针变量 int* p = &a;//把a的地址赋值给p
#include <stdio.h>
#include <stdlib.h>
main() {
int * p; //p 是变量的名字, int * 是一个类型 //这个变量存放的是int类型变量的地址。
int i =3;
p=&i;
system(“pause”);
}
/*
int * p; //p是变量的名字, int * 表示p变量的数据类型是存放int类型的地址的数据类型
int * p; 不表示定义了一个名字叫做*p的变量
int * p; 应该这样理解: p是变量名, int *是数据类型 ,p变量的数据类型是int*
所谓int * 类型 实际就是存放int变量地址的类型
int i = 3;
p = &i;
1. p保存了i的地址, 因此p指向i
2. p不是i,i也不是p,修改p的值不影响i的值,修改i的值也不会影响p的值
3. 如果一个指针变量指向了某个普通变量, 则 *指针变量 就完全等同于 普通变量
例子:
如果p是个指针变量,并且p存放了普通变量i的地址
则p指向了普通变量i
*p 就完全等同于 i
在所有出现*p的地方都可以替换成i
在所有出现i的地方都可以替换成*p
*p 就是以p的内容为地址的变量
*/
指针和指针变量的关系:
指针就是地址,地址就是指针
地址就是内存单元的编号
指针变量是存放地址的变量
指针和指针变量是两个不同的概念
但是要注意: 通常我们叙述时会把指针变量简称为指针,实际它们含义并不一样
* 的三种用法
1. 乘法
2. int* p:定义一个指针变量p,p中存放一个内存地址,这个地址所存放的数据规定是int型
3. *p:取出p中保存的内存地址存放的数据
#include <stdio.h>
#include <stdlib.h>
main(){
int a =12; //在内存中开辟一个空间
int* p = &a; //定义指针变量 p ,并把a的地址赋值给p;
int** q = &p; //二级指针,指向指针变量的指针;
printf("%#x \n",&a); //&运算是用来取地址的
printf("a的地址 %#x \n",p);
printf("a的值 %d \n",*p);
}
如下图上述代码中的变量a 指针p q在内存中的关系图

多级指针:
#include <stdio.h>
#include <stdlib.h>
main(){
int a = 33;
int* p = &a; //注意int* 可以看作一个特殊类型,和普通的变量声明(int a = 33)对比的去理解
int** q = p;
int*** m = q;
printf("a的值%d\n",a);
printf("a的值%d\n",*p);
printf("a的值%d\n",**q); //**q相当于*(*q),*q等价于p ,*p 就是a的值;
printf("a的值%d\n",***m);//***m等价于**(*m),而*m等价于q; 一层层替换就好理解了
}
指针常见问题
#include <stdio.h>
#include <stdlib.h>
main(){
int *p; //野指针,不能随便赋值例如 p = 2,这种是错误的;
int i ;
p = &i;
*p = 11;
printf("i 的值%d \n",*p);
double a = 2.11;
p = &a;
printf("i 的值%lf \n",*p);
double *q ;
double b = 3.22;
q = &b;
printf("b的值%lf \n",*q);
}
C语言值传递和地址传递(引用传递)
- 数据传递
所有语言所有平台,都只有值传递,引用传递传递的值是内存地址
值传递(目的:互换a,b两个数值,这种值传递无法达到目的)
#include <stdio.h>
#include <stdlib.h>
main(){
int a = 5;
int b = 12;
printf("a = %d,b = %d \n",a ,b);
swp(a , b);
printf("a = %d,b = %d \n ",a ,b);
}
void swp(int i , int j){
int tmp = i;
i = j;
j=tmp;
}
以上运行结果
a = 5,b = 12
a = 5,b = 12
- 地址传递(目的:互换a,b两个数值,地址传递可以达到目的)
#include <stdio.h>
#include <stdlib.h>
main(){
int a = 5;
int b = 12;
printf("a = %d,b = %d \n ",a ,b);
swp(&a , &b);
printf("a = %d,b = %d \n ",a ,b);
}
void swp(int *i , int *j){
//int *tmp = *i;
int tmp = *i;
*i = *j;
*j= tmp;
}
运行结果:
a = 5,b = 12
a = 12,b = 5
通过传递地址,返回多个数据
#include <stdio.h>
#include <stdlib.h>
main(){
int a = 5;
int b = 12;
printf("a = %d,b = %d \n",a ,b);
swp(&a , &b);
printf("a = %d,b = %d \n ",a ,b);
}
void swp(int *i , int *j){
*i += 15 ;
*j += +10;
*j = ++*j;
}
运行结果:
a = 5,b = 12
a = 20,b = 23
主函数中获取子函数中的地址
#include <stdio.h>
#include <stdlib.h>
main(){
int* m;
function1(&m);
printf("主函数中获取i的值%d \n", *m);
system("pause");
}
void function1(int** a){
int i = 20;
printf("i的值 %d \n",i);
*a = &i;
}
画图解释以上代码:

数组
一维数组名是个指针常量 ,C中不检测数组长度,所以也没有Java中数据下标越界的异常;
#include <stdio.h>
#include <stdlib.h>
main(){
char c[] = "Hello";
int i[5] = {1,2,3,4,5};
printf("%c \n",c[0]);
printf("%#x \n",&c[0]);
printf("%#x \n",&c[1]);
printf("%#x \n",&c[2]);
printf("%#x \n",&c[3]);
printf("%#x \n",&c);//数组的地址就是数组中第一个元素的地址
char* cp = &c;
printf("%c \n",*cp);//取出数组中第一个元素
printf("%c \n",*(cp+1));//取出数组中第二个元素;指针可以做加减运算,但前提是地址是连续的
printf("%c \n",*(c+1));//c[1]等价于*(c+1) int* ip =&i; printf("%#x \n",(ip+0));
printf("%#x \n",(ip+1));//第二元素的地址和第一个元素的地址相差了4,因为int值在内存中占4个字节 printf("%#x \n",(ip+2));
printf("%#x \n",(ip+3));
}
指针长度
#include <stdio.h>
#include <stdlib.h>
main(){
int* ip;
char* cp;
double* dp;
int* mp;
int i;
char c;
double d;
ip=&i;
cp = &c;
dp = &d;
printf("%d \n",sizeof(ip)); //打印输出都是4,长度是4个字节
printf("%d \n",sizeof(cp));
printf("%d \n",sizeof(dp));
printf("%d \n",ip-mp); //没有任何意义,错误写法
}
动态申请堆内存,C中是通过malloc函数完成的;
#include <stdio.h>
#include <stdlib.h>
main(){
int i = 10 ;//栈内存
char a[10];//栈内存
int* p;
p = malloc(sizeof(int) * 10);//申请用于存放10个int类型大小的内存空间;堆内存中
*p = 21;
*(p+1) = 11;
printf("%#x \n",p);
printf("%d \n",*(p+1));
free(p);//释放后不能在使用指针p了
}
结构体
#include <stdio.h>
#include <stdlib.h>
//函数也是有地址的,所以可以定义函数指针
void study(){
printf("调用了study()函数\n");
}
//定义结构体
struct student{
int age;
int height;
char sex;
//结构体不能定义函数 ,但可以定义函数指针;函数的指针定义int (*pf)(int x, int y);
//定义函数指针
void (* studyS)();
}
main(){
//struct student st = {22,180,'w'};
//printf("结构体长度:%d\n",sizeof(st));
//定义结构体变量
struct student st = {22,180,'w',study}; //把函数名study传进去,studyS函数指针就指向了study()函数
printf("%d \n",st.age);
printf("结构体长度:%d\n",sizeof(st));
//第一种函数调用;
st.studyS();
//第二种,结构体也有指针
struct student* stp = &st;
(*stp).studyS();
//第三种,这种调用stp必须是结构体指针
stp->studyS();
}
联合体
联合变量可被赋予任一成员值,但每次只能赋一种值, 赋入新值则冲去旧值。
#include <stdio.h>
#include <stdlib.h>
main(){
//联合体定义
union{char c;int i;short s} un; //多个数据类型之间用;分号分隔
un.c = 'm';
un.i = 3;
printf("%c\n",un.c);
printf("%d\n",un.i);
printf("%d\n",sizeof(un));//联合体的长度由类型种所有变量长度的最大长度绝对,例如un的最大长度 就是int的长度;
}
枚举
#include <stdio.h>
enum WeekDay
{
Monday = 20,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
};
int main(void)
{
//int day;
enum WeekDay day = Sunday;
printf("%d\n",day);
system("pause");
return 0;
}
自定义类型
#include <stdio.h>
#include <stdlib.h>
typedef int hehe;
main(){
hehe i =10; //hehe相当与int类型
printf("%d \n",i);
}
本文深入解析C语言中的指针概念,包括基本定义、指针变量、多级指针、数组与指针的关系、动态内存分配及结构体与联合体中的指针应用,通过实例帮助理解指针操作。

5499

被折叠的 条评论
为什么被折叠?



