依稀记得10年前的大学第一门课就是它——c语言,而指针作为c语言的核心之一,当时一直难以理解,从而转战java。而今10余年过去了,依然还是放不下它,也同时为了阅读openJDK源码做准备,就重新拾起。其实就是因为喜欢研究底层这个癖好,才让我走上了不归路。没办法,重新拾起c语言基础。
其实对技术学习本来就应该是兴趣驱动,但目前太多人学习技术都过于功利,工作中用什么学什么,失去了自己对技术的追求,我又何尝不是呢?其实都是为了生存罢了。
不再感慨了,下面一小段代码,总结了指针的基础:
#include <stdio.h>
#include <stdlib.h>
struct Person
{
char name;
int age;
};
int test(int a,int b) {
printf("%d %d\n", a, b);
return a + b;
};
int test2(int a,int b) {
printf("%d %d\n", a, b);
return a - b;
};
void test3(struct Person persons) {
persons.age = 10;
//printf("persons.age: %d\n", persons.age);
}
void test4(struct Person *persons_p) {
persons_p->age = 10;
//printf("persons.age: %d\n", persons_p->age);
}
int main() {
// 变量a,其内存地址为0x7ffee3a1ab38
/**
* a
* 0x7ffee3a1ab38
* |——————————————————————|
* | 10 |
* |——————————————————————|
*
*/
int a = 10;
// int *pInt 定义一个指针类型变量,pInt本身会分配一个内存空间,即分配一个内存地址,pInt本身存放的值为变量a的内存地址
// &a即取a的内存地址0x7ffee3a1ab38
/**
*
* a
* pInt ——————————————————————> 0x7ffee3a1ab38
* 0x7ffee1ab2b30
* |——————————————————————| |——————————————————————|
* | 0x7ffee3a1ab38 | | 10 |
* |——————————————————————| |——————————————————————|
*
*
*
*/
int *pInt = &a;
// '*'即定义一个指针类型的变量,变量值为内存地址,'&'即取地址符,取得指定变量的内存地址
printf("%p\n", &a); //输出:0x7ffeef5e5b38,a的内存地址
printf("%p\n", pInt); //输出:0x7ffeef5e5b38,指针变量pInt的值
printf("%p\n", &pInt); //输出:0x7ffeef5e5b30,指针变量pInt的内存地址
printf("%d\n", *pInt); //输出:10,*pInt即解引用,取出其引用地址变量所存储的值,即变量a的值
/**
* 再看一个例子
*/
// *p:p的值为0x11223344,它的内存地址为0x7ffee5cafb24
int *p = 0x11223344;
// 变量p的值赋值给a1,即a1=0x11223344
int a1 = p;
// a1为变量p的值0x11223344,&a1为变量a1的实际内存地址
printf("%p\n", a1); //输出:0x11223344
printf("%p\n", &a1); //输出:0x7ffee264cb24
printf("%p\n", &p); //输出:0x7ffee264cb28
/**
* '**':指向指针的指针,其实这么解释'**'的人就有点不负责任了,什么叫指向指针的指针呢?
* 其实就是一个二维指针,看图:
* a
* pInt ——————————————————————> 0x7ffee3a1ab38
* pInt1 ——————————————————————> 0x7ffee1ab2b30
* |——————————————————————| |——————————————————————| |——————————————————————|
* | 0x7ffee1ab2b30 | | 0x7ffee3a1ab38 | | 10 |
* |——————————————————————| |——————————————————————| |——————————————————————|
*
* **pInt1就代表pInt1指向pInt指针变量,*pInt1即取得pInt1的引用PInt的值,即0x7ffee3a1ab38。
* *(*pInt1)即取得pInt的引用a的值,即为10。
*
*/
int **pInt1 = &pInt;
printf("*pInt1:%p\n", *pInt1);
printf("**pInt1:%d\n", *(*pInt1));
printf("%p\n", &pInt1);
/**
* 常量指针,指针常量
*/
// 常量指针:能修改指针的指向,不能修改指针的实际值
const int * c = 0x321312;
//*c = 1; // 此行报错
// 指针常量:能修改指针的实际值,不能修改指针的指向
int * const c1 = 1;
//c1 = &a; // 此行报错
// 常量指针+指针常量:即不能修改指针指向,也不能修改值
const int * const c2 = 2;
//*c2 = 1; // 此行报错
//c2 = &a; // 此行报错
/**
* 函数指针
*/
// 即定义了返回值为int类型,参数为int,int类型的函数指针,p_test直接接收返回值
int (*p_test) (int, int);
p_test = test(1,2);
p_test = test2(1,2);
printf("p_test:%d\n", p_test);
/**
* 不同类型变量转换
*/
// int 转 char,因为int类型在64位机器上占4个字节
int *t = 0x11223344;
// int转char,char占1个字节,所以只能取变量t中的一个字节,因为是小端机(什么是小端,自己普及),所以取得44,大端应该输出11
char s = (char *)t;
// int 转 long double
long double *d = (long double *) t;
printf("%p\n", s); //输出:0x44
printf("%p\n", d); //输出:0x11223344
/**
* 通过指针方式操作数组
*/
// 数组,通过指针的方式取char数组中的其中一个字符。
char name[] = "test";
// 这行是通过指针方式来获取name变量的第二个字符,因为char占1个字节,所以name+1即取得指向test数组的index为2的位置,
// 即*(name + 1)取得对于的char字符e
char i = *(name + 1);
printf("%c\n", i); //输出:e
/**
* 函数之值传递、引用传递
*/
// 值传递,传递的变量本身,不会修改变量的值
struct Person person1;
person1.age = 1;
test3(person1);
printf("%d\n", person1.age); // 输出:1
// 引用传递,传递的是变量的内存地址,会修改变量的值
struct Person person2;
person2.age = 1;
test4(&person2);
printf("%d\n", person2.age); // 输出:10
return 0;
}
本文这小段代码挺小白的,因为对于c语言来说,我也是个小白。