c语言基础(六)

205 阅读4分钟

1.指针和内存单元

	指针: 地址。

	内存单元: 计算机中内存最小的存储单位。——内存单元。大小一个字节。 每一个内存单元都有一个唯一的编号(数)。

		   称这个内存单元的编号为 “地址”。

	指针变量:存地址的变量。

2.指针定义和使用:

	int a = 10;

	int* p = &a;			int* p;--- windows;	int *p ---Linux       int * p ;

	int a, *p, *q, b;

	*p = 250;			指针的 解引用。 间接引用。

	*p : 将p变量的内容取出,当成地址看待,找到该地址对应的内存空间。

		如果做左值: 存数据到空间中。

		如果做右值: 取出空间中的内容。


	任意“指针”类型大小:

		指针的大小与类型 无关。 只与当前使用的平台架构有关。   32位:4字节。	 64位: 8字节。
                
由于int* p = &a;的本质是给p赋值,所以*应该和int写在一起,表示定义一个int*类型的变量,其值为内存地址,这也就是为什么p = &b;是合法的原因了。

3.野指针:

	1) 没有一个有效的地址空间的指针。

		int* p;

		*p = 1000;

	2)p变量有一个值,但该值不是可访问的内存区域。
		
		int *p = 10;

		*p = 2000;

	【杜绝野指针】

4.空指针:

	int *p = NULL;     #define NULL ((void *)0)

	*p 时 p所对应的存储空间一定是一个 无效的访问区域。

5.万能指针/泛型指针(void *):

可以接收任意一种变量地址。但是,在使用【必须】借助“强转”具体化数据类型。
		char ch = 'R';

		void *p;  // 万能指针、泛型指针
		
		p = &ch;

		printf("%c\n", *(char *)p);

6.const关键字:

修饰变量:
	const int a = 20;
	int *p = &a;
	*p = 650;
	printf("%d\n", a);


修饰指针:
	const int *p;
		可以修改 p
		不可以修改 *p。
	int const *p;
		同上。
	int * const p;
		可以修改 *p
		不可以修改 p。
	const int *const p;
		不可以修改 p。
		不可以修改 *p。
	总结:const 向右修饰,被修饰的部分即为只读。

	常用:在函数形参内,用来限制指针所对应的内存空间为只读。

7.指针和数组:

	数组名:  
		【数组名是地址常量】 --- 不可以被赋值。	 ++ / -- / += / -= / %= / /=  (带有副作用的运算符)

		指针是变量。可以用数组名给指针赋值。 ++ -- 

	取数组元素:

		int arr[] = {1,3, 5, 7, 8};
		int *p = arr;  
		arr[i] == *(arr+0) == p[0] == *(p+0)
	指针和数组区别:
		1. 指针是变量。数组名为常量。
		2. sizeof(指针) ===》 4字节 / 8字节
		   sizeof(数组) ===》 数组的实际字节数。
	指针++ 操作数组:
		int arr[] = { 1, 2, 4, 5, 6, 7, 8, 9, 0 };
		int *p = arr;		
		for (size_t i = 0; i < n; i++)
		{
			printf("%d ", *p);
			p++;  // p = p+1;   一次加过一个int大小。 一个元素。
		}
		p的值会随着循环不断变化。打印结束后,p指向一块无效地址空间(野指针)。

8.指针加减运算:

	数据类型对指针的作用:
		1)间接引用:
			决定了从指针存储的地址开始,向后读取的字节数。  (与指针本身存储空间无关。)
		2)加减运算:
			决定了指针进行 +1/-1 操作向后加过的 字节数。
	指针 * / % : error!!!
	指针 +- 整数:
		1) 普通指针变量+-整数
			char *p; 打印 p 、 p+1  偏过 1 字节。
			short*p; 打印 p 、 p+1  偏过 2 字节。
			int  *p; 打印 p 、 p+1  偏过 4 字节。		
		2)在数组中+- 整数
			short arr[] = {1, 3, 5, 8};
			int *p = arr;
			p+3;			// 向右(后)偏过 3 个元素
			p-2;			// 向前(左)偏过 2 个元素
		3)&数组名 + 1
			加过一个 数组的大小(数组元素个数 x sizeof(数组元素类型))
	指针 +- 指针:
		指针 + 指针: error!!!
		指针 - 指针:
			1) 普通变量来说, 语法允许。无实际意义。【了解】
			2) 数组来说:偏移过的元素个数。

9.指针实现 strlen 函数:

	char str[] = "hello";
	char *p = str;
	while (*p != '\0')
	{
		p++;
	}
	p-str; 即为 数组有效元素的个数。
#include<stdio.h>
// 计算出来的比sizeof (arr) / sizeof (char)少一位
int get_str_len(char* p){
    int count = 0;
    while(*p++ != '\0'){
        count++;
    }
    return count;
}

// 计算出来的与sizeof (arr) / sizeof (char)位数相同
int get_str_len2(char* p){
    char* _p = p;
    while(*_p++ != '\0'){}
    return _p - p;
}

10.指针比较运算:

	1) 普通变量来说, 语法允许。无实际意义。
	2) 数组来说:     地址之间可以进行比较大小。
			  可以得到,元素存储的先后顺序。

	3int *p;
	    p = NULL;		// 这两行等价于: int *p = NULL;
	    if (p != NULL)
		printf(" p is not NULL");
	    else 
		printf(" p is NULL");

11.指针数组:

	一个存储地址的数组。数组内部所有元素都是地址。
	1) 
		int a = 10;
		int b = 20;
		int c = 30;
		int *arr[] = {&a, &b, &c}; // 数组元素为 整型变量 地址
	2) 
		int a[] = { 10 };
		int b[] = { 20 };
		int c[] = { 30 };
		int *arr[] = { a, b, c }; // 数组元素为 数组 地址。	
	指针数组本质,是一个二级指针。
	二维数组, 也是一个二级指针。

12.多级指针:

	int a = 0;
	int *p = &a;  				一级指针是 变量的地址。
	int **pp = &p;				二级指针是 一级指针的地址。
	int ***ppp = &pp;			三级指针是 二级指针的地址。	
	int ****pppp = &ppp;			四级指针是 三级指针的地址。	【了解】
	......
	多级指针,不能  跳跃定义!
	对应关系:
	ppp == &pp;			三级指针
	*ppp == pp == &p; 			二级指针
	**ppp == *pp == p == &a				一级指针
	***ppp == **pp == *p == a				普通整型变量

	*p : 将p变量的内容取出,当成地址看待,找到该地址对应的内存空间。
		如果做左值: 存数据到空间中。
		如果做右值: 取出空间中的内容。

13.指针和函数:

	传值和传址:
	指针做函数参数:
	数组做函数参数:
	指针做函数返回值:
	数组做函数返回值:
  • 练习1:比较两个字符串:
    • 比较 str1 和 str2, 如果相同返回0, 不同则依次比较ASCII码,str1 > str2 返回1,否则返回-1
// 比较两个字符串的大小:规则:从左往右只要某一位比较大,整体就大  
int compare_str (char* str_a, char* str_b) {  
    while (*str_a != '\0' || *str_b != '\0') {  
        if(*(str_a++) > *(str_b++)){  
            return 1;  
        } else if (*(str_a++) < *(str_b++)) {  
            return -1;  
        } else {  
            continue;  
        }  
    }  
    return 0;  
}  
    // char* str1 = "abc1234";  
    // char* str2 = "abc1234";  
    // int rst = compare_str(str1, str2);  
    // printf("%d\n", rst);
  • 练习2:字符串拷贝
char* copy_str(char* src, char* tar) {  
    while (*(src) != '\0') {  
        *(tar++) = *(src++);  
    }  
    return tar;  
}  
    // char* strx = "abc1234";  
    // char tar[7] = {0};  
    // copy_str(strx, tar);  
    // printf("--%s\n", tar);
  • 练习3:在字符串中查找字符出现的位置