从一个大一学生的视角记录我认为值得学习的内容
一、基本使用
前面的用法很直观,指针指向别的变量,存的是对方的地址。随便看看几篇博客,多敲敲就会了
#include <stdio.h>
#include <iostream>
using namespace std;
int main() {
int var1 = 105;
float var2 = 21;
int *p1 = &var1;
cout << *p1;//105 读取值
cout << p1;//0x6ffe1c 每个人运行结果可能不同
float *p2 = &var2;//指针还有类型?实际上指指针的指向
//指向的直接意思就是指针变量所保存的其他的地址单元中所存放的数据类型。
//不论指向的数据类型为那种,指针变量其本身永远为整型,因为它保存的地址。
return 0;
}
二、指针与数组
数组是连续存储的,意味着可以用a[0]的地址来代表整个数组
#include <stdio.h>
#include <iostream>
using namespace std;
int main() {
int a[10];
int b[10] = {};
double c[10];
//1
int *p1 = a;//&a[0]
int *p2 = b;
double *p3 = c;
//2
//数组名是常量
//可以
//int *p1 = a;
//不能 a = p1;
//3
cout << p1 << endl;
cout << p2 << endl;
cout << p3 << endl;
printf("%p %p %p\n", p1, p2, p3);//%p是pointer的缩写 64位的数据
printf("%x %x %x\n", p1, p2, p3);//%x会把众多前导零删掉
//4
printf("%x\n", a + 4);
printf("%x\n", &a[4]);
printf("%x", p1 + 4);//三者等价
return 0;
}
三、字符数组
在尝试的过程中发现char数组比较特别,没想到真能发现什么
1.字符串即地址
char *s ;
s = "China";
C语言中编译器会给字符串常量分配地址,如果 "China", 存储在内存中的 0x3000 0x3001 0x3002 0x3003 0x3004 0x3005 .
s = "China" ,意识是什么,对了,地址。
其实真正的意义是 s ="China" = 0x3000;
看清楚了吧 ,你把China 看作是字符串,但是编译器把它看作是地址 0x3000,即字符串常量的本质表现是代表它的第一个字符的地址。。。。。。。。。。
s = 0x3000
这样写似乎更符合直观的意思。。。
搞清楚这个问题。。
那么 %s ,它的原理其实也是通过字符串首地址输出字符串,printf("%s ", s); 传给它的其实是s所保存的字符串的地址。。。
2.char a[]与char *s的区别
char * 与 char a[ ] 的本质区别:
当定义 char a[10 ] 时,编译器会给数组分配十个单元,每个单元的数据类型为字符。。
而定义 char *s 时, 这是个指针变量,只占四个字节,32位,用来保存一个地址。。
sizeof(a) = 10 ;
sizeof(s) = ?
当然是4了,编译器分配4个字节32位的空间,这个空间中将要保存地址。。。
printf("%p",s);
这个表示 s 的单元中所保存的地址。。
printf("%p",&s);
这个表示变量本身所在内存单元地址。。。。,不要搞混了。。
3.二级指针
#include <stdio.h>
#include <iostream>
using namespace std;
int main() {
//二级指针
char **s = (char **)malloc(sizeof(char **));
//两者等价,至少在结果上一样
char **s;
s = (char **)malloc(sizeof(char **));
*s = "hello world";
printf("%s", *s);
return 0;
}
#include<iostream>
using namespace std;
void buf(char **s){
*s = "there is a message";
}
int main(){
char *s;
buf(&s);
printf("%s\n", s);//输出 there is a message
char *a = "China";
printf("%c", *a);//a指向的是第一个字母 C
}
四、指针传递和引用传递
值传递:
形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,
不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。
指针传递:
形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作
引用传递:
形参相当于是实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈
中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过
栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
五、函数指针
六、一些细节
参考文献深入 理解char * ,char ** ,char a[ ] ,char *a[] 的区别C中哪些方式定义的字符串,其末尾会自动添加‘\0’