# 概述
# 内存
- 存储器:计算机的组成中,用来存储数据和程序的部件
- 内存:内部存储器,暂存程序和数据
- 外村:外部存储器,用来长期存储程序和数据
内存是沟通CPU和外部存储器的桥梁,CPU通过内存来访问外部存储器
- 暂存放CPU要处理的数据和程序
- 暂存与硬盘等外部存储器交换的数据
# 物理存储器和存储地址空间
物理存储器:内存条,内存条上的每一个存储单元都有一个唯一的编号,称为物理地址
存储地址空间:内存条上所有存储单元的集合,每一个存储单元都有一个唯一的编号,称为存储地址
# 内存地址
- 将内存抽象成一个很大的数组,每个元素都有一个唯一的编号,称为内存地址
- 内存地址是一个无符号整数,用16进制表示
- 内存地址的范围:0x00000000 ~ 0xFFFFFFFF
# 指针和指针变量
- 指针:内存地址的别名
- 指针变量:存储内存地址的变量
# 指针的定义和使用
# 指针的定义
- 指针变量的定义:
数据类型 *指针变量名;
- 指针变量的初始化:
指针变量名 = &变量名;
- 指针变量的使用:
*指针变量名
*
操作符操作的是指针变量指向的内存空间
include <stdio.h>
int main() {
int a = 10; //定义一个变量a,值为10
int *p; //定义一个指针变量p
p = &a; //将变量a的地址赋值给指针变量p
printf("a的值为:%d\n", a); //打印变量a的值
printf("a的地址为:%p\n", &a); //打印变量a的地址
printf("p的值为:%p\n", p); //打印指针变量p的值
printf("p的地址为:%p\n", &p); //打印指针变量p的地址
printf("*p的值为:%d\n", *p); //打印指针变量p指向的内存空间的值
return 0;
}
# 指针间接修改变量的值
#include <stdio.h>
int main() {
int a = 10; //定义一个变量a,值为10
int *p; //定义一个指针变量p
p = &a; //将变量a的地址赋值给指针变量p
*p = 20; //通过指针间接修改变量a的值
printf("a的值为:%d\n", a); //打印变量a的值
return 0;
}
# 指针的大小
指针变量的大小与操作系统有关
- 32位操作系统:4个字节
- 64位操作系统:8个字节
sizeof(指针变量名)
可以获取指针变量的大小
#include <stdio.h>
int main() {
int a = 10; //定义一个变量a,值为10
int *p; //定义一个指针变量p
p = &a; //将变量a的地址赋值给指针变量p
printf("指针变量p的大小为:%lu\n", sizeof(p)); //打印指针变量p的大小
return 0;
}
# 野指针和空指针
- 野指针:指针变量指向非法的内存空间
- 空指针:指针变量指向内存编号为0的空间,空指针不指向任何合法的内存空间
WARNING
- 空指针不是野指针
- 空指针指向的内存空间是不可以访问的
- 空指针不指向任何合法的内存空间
#include <stdio.h>
int main() {
int *p = NULL; //定义一个空指针
printf("空指针p的值为:%p\n", p); //打印空指针p的值
printf("空指针p的大小为:%lu\n", sizeof(p)); //打印空指针p的大小
return 0;
}
# 万能指针 void *
void *
是一种特殊的指针类型,可以用来存放任意类型的地址
#include <stdio.h>
int main() {
int a = 10; //定义一个变量a,值为10
int *p = &a; //定义一个指针变量p,指向变量a
void *p1 = &a; //定义一个万能指针p1,指向变量a
printf("指针变量p的值为:%p\n", p); //打印指针变量p的值
printf("万能指针p1的值为:%p\n", p1); //打印万能指针p1的值
return 0;
}
# const
修饰指针变量
const
修饰指针变量,表示指针变量指向的内存空间的值不能修改
#include <stdio.h>
int main() {
int a = 10; //定义一个变量a,值为10
int b = 20; //定义一个变量b,值为20
int *const p = &a; //定义一个指针变量p,指向变量a
printf("指针变量p的值为:%p\n", p); //打印指针变量p的值
printf("指针变量p指向的值为:%d\n", *p); //打印指针变量p指向的值
//p = &b; //err, 指针变量p的值不能修改
*p = 30; //ok, 指针变量p指向的值可以修改
printf("指针变量p指向的值为:%d\n", *p); //打印指针变量p指向的值
return 0;
}
# 指针和数组
# 数组名和指针
- 数组名:数组首元素的地址
- 指针变量:指向数组首元素的指针变量
#include <stdio.h>
int main() {
int arr[5] = {1, 2, 3, 4, 5}; //定义一个数组arr
printf("数组arr的地址为:%p\n", arr); //打印数组arr的地址
printf("数组arr的地址为:%p\n", &arr[0]); //打印数组arr的地址
printf("数组arr的地址为:%p\n", &arr); //打印数组arr的地址
printf("数组arr的地址为:%p\n", &arr + 1); //打印数组arr的地址
printf("数组arr的地址为:%p\n", arr + 1); //打印数组arr的地址
printf("数组arr的地址为:%p\n", &arr[0] + 1); //打印数组arr的地址
printf("数组arr的地址为:%p\n", &arr[1]); //打印数组arr的地址
printf("数组arr的地址为:%p\n", &arr[1] + 1); //打印数组arr的地址
printf("数组arr的地址为:%p\n", arr[1] + 1); //打印数组arr的地址
printf("数组arr的地址为:%p\n", *(arr + 1)); //打印数组arr的地址
printf("数组arr的地址为:%p\n", *arr + 1); //打印数组arr的地址
return 0;
}
# 指针操作数组
#include <stdio.h>
int main() {
int arr[5] = {1, 2, 3, 4, 5}; //定义一个数组arr
int i = 0;
for (i = 0; i < 5; i++) {
printf("%d\n", *(arr + i));
}
printf("arr[0]的地址为:%p\n", &arr[0]); //打印数组arr的地址
int *p = arr; //定义一个指针变量p,指向数组arr
for (i = 0; i < 5; i++) {
printf("%d\n", *(p + i));
}
for (i = 0; i < 5; i++) {
p[i] = 2 * i;
}
}
# 指针加减运算
- 指针加减整数:指针向前或向后移动指定的元素个数
- 指针加减指针:两个指针相减,得到的是两个指针之间的元素个数
#include <stdio.h>
int main(){
int a;
int *p = &a;
int *p1 = p + 1;
printf("p的值为:%p\n", p);
printf("p1的值为:%p\n", p1);
printf("p1 - p的值为:%ld\n", p1 - p);
char b=0;
char *p2 = &b;
char *p3 = p2 + 1;
printf("p2的值为:%p\n", p2);
printf("p3的值为:%p\n", p3);
printf("p3 - p2的值为:%ld\n", p3 - p2);
}
通过改变指针指向操作数组元素:
#include <stdio.h>
int main(){
int arr[5] = {1, 2, 3, 4, 5}; //定义一个数组arr
int *p = arr; //定义一个指针变量p,指向数组arr
int i = 0;
for (i = 0; i < 5; i++) {
printf("%d\n", *(p + i));
}
p = &arr[4];
for (i = 0; i < 5; i++) {
printf("%d\n", *(p - i));
}
}
# 指针数组
指针数组:数组中存放的是指针变量
#include <stdio.h>
int main() {
int a = 10; //定义一个变量a,值为10
int b = 20; //定义一个变量b,值为20
int c = 30; //定义一个变量c,值为30
int *arr[3] = {&a, &b, &c}; //定义一个指针数组arr,存放指针变量
int i = 0;
for (i = 0; i < 3; i++) {
printf("%d\n", *(arr[i]));
}
return 0;
}
# 多级指针
- C语言允许有多级指针存在, 在实际的程序中一级指针最常用,其次是二级指针。
- 一级指针:指向变量的指针
- 二级指针:指向一级指针的指针
- 三级指针:指向二级指针的指针
#include <stdio.h>
int main(){
int a = 10; //定义一个变量a,值为10
int *p = &a; //定义一个指针变量p,指向变量a
int **p1 = &p; //定义一个二级指针变量p1,指向指针变量p
int ***p2 = &p1; //定义一个三级指针变量p2,指向二级指针变量p1
printf("a的值为:%d\n", a); //打印变量a的值
printf("a的地址为:%p\n", &a); //打印变量a的地址
printf("p的值为:%p\n", p); //打印指针变量p的值
printf("p的地址为:%p\n", &p); //打印指针变量p的地址
printf("p1的值为:%p\n", p1); //打印二级指针变量p1的值
printf("p1的地址为:%p\n", &p1); //打印二级指针变量p1的地址
printf("p2的值为:%p\n", p2); //打印三级指针变量p2的值
printf("p2的地址为:%p\n", &p2); //打印三级指针变量p2的地址
return 0;
}
# 指针和函数
# 函数形参改变实参的值
#include <stdio.h>
void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}
void swap1(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int a = 10;
int b = 20;
printf("a的值为:%d\n", a);
printf("b的值为:%d\n", b);
swap(a, b);
printf("a的值为:%d\n", a);
printf("b的值为:%d\n", b);
swap1(&a, &b);
printf("a的值为:%d\n", a);
printf("b的值为:%d\n", b);
return 0;
}
# 函数返回指针
#include <stdio.h>
int *getMax(int *a, int *b) {
if (*a > *b) {
return a;
} else {
return b;
}
}
int main() {
int a = 10;
int b = 20;
int *p = getMax(&a, &b);
printf("p的值为:%p\n", p);
printf("p的值为:%d\n", *p);
return 0;
}
# 函数指针
- 函数指针:指向函数的指针变量
#include <stdio.h>
int getMax(int a, int b) {
return a > b ? a : b;
}
int main() {
int a = 10;
int b = 20;
int (*p)(int, int) = getMax;
printf("p的值为:%p\n", p);
printf("p的值为:%d\n", p(a, b));
return 0;
}
# 指针和字符串
# 字符指针
- 字符指针:指向字符串的指针变量
#include <stdio.h>
int main() {
char *p = "hello world";
printf("p的值为:%p\n", p);
printf("p的值为:%s\n", p);
return 0;
}
# 字符指针做函数参数
#include <stdio.h>
void printStr(char *p) {
printf("p的值为:%p\n", p);
printf("p的值为:%s\n", p);
}
int main() {
char *p = "hello world";
printf("p的值为:%p\n", p);
printf("p的值为:%s\n", p);
printStr(p);
return 0;
}
# const
修饰的指针变量
const
修饰的指针变量,指针变量指向的内存空间的值不能修改
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void){
const char *p = "hello world";
printf("p的值为:%p\n", p);
printf("p的值为:%s\n", p);
//p[0] = 'H'; //err, 指针变量p指向的内存空间的值不能修改
p = "hello world"; //ok, 指针变量p指向的内存空间的值可以修改
printf("p的值为:%p\n", p);
}
# 指针数组做为main函数的参数
main
函数是操作系统调用的,第一个参数是argc
,第二个参数是argv
,argv
是一个指针数组,数组中的每一个元素都是一个指针,指向一个字符串
#include <stdio.h>
int main(int argc, char *argv[]){
char*a[]={ "hello", "world", "!" };
int i;
for (i = 0; i < argc; i++) {
printf("%s\n", argv[i]);
}
return 0;
}
# 字符串处理函数
函数名 | 功能 | 参数 | 返回值 | 头文件 |
---|---|---|---|---|
strlen | 计算字符串的长度 | const char *str | size_t | string.h |
strcpy | 复制字符串 | char *dest, const char *src | char * | string.h |
strcat | 字符串拼接 | char *dest, const char *src | char * | string.h |
strcmp | 字符串比较 | const char *str1, const char *str2 | int | string.h |
strchr | 查找字符在字符串中第一次出现的位置 | const char *str, int c | char * | string.h |
strstr | 查找字符串在字符串中第一次出现的位置 | const char *haystack, const char *needle | char * | string.h |
strtok | 分割字符串 | char *str, const char *delim | char * | string.h |
strerror | 根据错误编号获取错误信息 | int errnum | char * | string.h |
stmcpy | 复制字符串 | char *dest, const char *src, size_t n | char * | string.h |
strncpy | 复制字符串 | char *dest, const char *src, size_t n | char * | string.h |
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void){
char *p = "hello world";
printf("p的值为:%p\n", p);
printf("p的值为:%s\n", p);
//p[0] = 'H'; //err, 指针变量p指向的内存空间的值不能修改
p = "hello world"; //ok, 指针变量p指向的内存空间的值可以修改
printf("p的值为:%p\n", p);
}