CDay07

指针基础

计算机的最小寻址单位:字节

变量的地址:变量第一个字节的地址

指针:简单来说指针就是地址

指针变量

指针变量:存放地址的变量,有时候也把指针变量称为指针

思考:指针变量只是存放变量的首地址,那怎么通过指针访问指针指向的对象?
答:声明时需要指明指针的基础类型(指针指向对象的类型),这样既知道了变量的首地址也知道了这个变量所占的内存大小,便可以访问此对象了。

int* p;
int 是指针的基础类型
*p 相当于变量 i 的别名,修改 *p 相当于修改 i

注意事项:
1、指针变量是 p ,不是 *p
2、指针变量类型是int*,而不是int

两个基本操作:&(取地址) 和 *(解引用)

例:

//取地址
int i = 1;
int *p;
p = &i;

解引用:通过指针访问指针指向的对象

通过 i 去访问:直接访问(访问一次内存)
通过 *p 去访问:间接访问(访问两次内存)

野指针问题

野指针:未初始化或指向未知区域的指针
例:

int *p1;
int *p2 = 0x7F;

对野指针进行解引用运算,会导致未定义的行为!

未定义的行为:程序可能崩溃也可能正常运行

指针变量的赋值

  • 通过取地址符赋值,p = &i
  • 通过另外一个指针赋值,p = q

注意事项:p = q 和 *p = *q 的区别
p = q:


*p = *q:


指针作为参数传递

指针作为参数传递的好处:可以在被调函数中访问并修改主调函数的参数。
示例:

#include<stdio.h>
void swap(int* pa, int* pb);

int main(void)
{
	int a = 3, b = 4;

	printf("交换前:a = %d, b = %d\n", a, b);
	swap(&a, &b);			//pa = &a, pb = &b
	printf("交换后:a = %d, b = %d\n", a, b);

	return 0;
}

void swap(int* pa, int* pb)
{
	int tmp = *pa;
	*pa = *pb;
	*pb = tmp;
}


指针和数组的关系

指针的算术运算

当指针指向数组元素时,可以通过指针的算术运算访问数组的其他元素

  • 指针加上一个整数,结果为指针
  • 指针减去一个整数,结果为指针
  • 两个指针相减(这两个指针应该指向同一个数组的元素),结果为整数

示例:

#include<stdio.h>

int main(void)
{
	int arr[] = { 0,1,2,3,4,5,6,7,8,9 };

	int* p = &arr[2];
	int* q = p + 3;
	p += 6;

	printf("*p = %d,*q = %d", *p, *q);

	return 0;
}

运行结果:

用指针处理数组

#include<stdio.h>

int main(void)
{
	int arr[] = { 0,1,2,3,4,5,6,7,8,9 };

	int sum = 0;
	for (int* p = arr; p < &arr[10]; p++)
	{
		//&arr[10]只会计算地址,并不会访问arr[10],因此不会发生数组越界现象
		sum += *p;
	}

	printf("sum = %d\n", sum);
	return 0;
}

注意 * 和 ++/-- 的组合形式:

  • *p++等价于*(p++):表达式的值为 *p,副作用为 p 自增。

  • (*p)++:表达式的值为*p,副作用为 *p 自增。

  • *++p 等价于 *(++p):表达式的值为 *(p + 1),副作用为 p 自增。

  • ++*p 等价于 ++(*p):表达式的值为 (*p) + 1,副作用为 (*p) 自增。

  • * 与 -- 的组合同理。

数组名可以作为指针使用(指向数组的第一个元素);指针也可以作为数组名使用。

即 p[i] = *(p + i)

字符串

C语言中没有专门的字符串类型,C语言中的字符串依赖字符数组存在。(C语言中的字符串是一个逻辑类型)

字符串的字面值

字符串的两种书写方式:

printf("I love xjl\n");
printf("I love xjl"
         "--by cz"); //在编译时,编译器会将两个相邻(两个字符串字面值之间仅有空白字符)字符串合并成一个

字符串字面值在内存中如何存储?

"abc" -----> (以空字符结尾)

'a' 'b' 'c' '\0'

"" ----->

'\0'

字符串变量


初始化

char name[10] = "Allen";    //浪费存储空间
char name[5] = "Allen";     //编译可通过,但是使用时会出现问题
char name[] = "Allen";      //推荐使用

字符串的初始化和字符指针的初始化

读写字符串

  • printf + %s
  • puts函数

注意:puts函数会在字符串后自动添加换行符

  • scanf + %s
  • gets函数

scanf + %s
匹配规则:跳过前置的空白字符,读取字符存入数组,直到遇到空白为止,并在后面添加 '\0'

缺陷

  1. 不能读取空白字符
  2. 不会检查数组是否越界

gets函数
匹配规则:不会跳过前置的空白字符,读取字符存入数组,直到遇到换行符为止,并将换行符替换成 '\0'

缺陷:

  1. 不会检查数组是否越界(可能会越界写入数据,造成未定义的行为)

以上两种读字符串的方法均不推荐,建议自己创造函数,做越界处理

字符串的库函数

strlen函数

//在标头 <string.h> 定义
size_t strlen( const char *str );

不会计算空字符

strcmp函数

int strcmp( const char *lhs, const char *rhs );

按照字典顺序比较(ASCII)

若字典序中 lhs 先出现于 rhs 则为负值。

若 lhs 与 rhs 比较相等则为零。

若字典序中 lhs 后出现于 rhs 则为正值。

strcpy函数

strcat函数

惯用法

//搜索字符串末尾

//str指向空字符
while(*str)
{
    str++;
}

//str指向空字符后一位
while(*str++)
  ;
posted @ 2023-02-04 14:27  MyXjl  阅读(16)  评论(0编辑  收藏  举报