C语言---Day7
16、指针
---windows电脑在数据存储是采用小端对齐
---指针就是内存地址,指针变量是用来存放内存地址的变量;每一个变量都有一个内存位置,每一个内存位置都定义了可使用 & 运算符访问的地址,它表示了在内存中的一个地址
---在32位操作系统下,所有指针类型都是4个字节大小; 在64位操作系统下,所有指针类型都是8个字节大小
---声明指针变量
int *ip; /* 一个整型的指针 */ double *dp; /* 一个 double 型的指针 */ float *fp; /* 一个浮点型的指针 */ char *ch; /* 一个字符型的指针 */
---使用指针:定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值;这些是通过使用一元运算符 * 来返回位于操作数所指定地址的变量的值
int var = 20; /* 实际变量的声明 */ int* ip; /* 指针变量的声明 */ ip = &var; /* 在指针变量中存储 var 的地址 */ printf("var 变量的地址: %p\n", &var); // var 变量的地址: 00BDFA20 /* 在指针变量中存储的地址 */ printf("ip 变量存储的地址: %p\n", ip); // ip 变量存储的地址: 00BDFA20 /* 使用指针访问值 */ printf("*ip 变量的值: %d\n", *ip); // *ip 变量的值: 20
// 通过指针间接改变变量的值 int a = 10; int* p; p = &a; *p = 100; printf("p的值为:%d", *p);
---声明指针变量时,赋值NULL指针;NULL 指针是一个定义在标准库中的值为零的常量
int *ptr = NULL; printf("ptr 的地址是 %p\n", ptr ); // ptr 的地址是 00000000
---野指针:指针变量指向一个未知的空间; 不要将一个变量的值直接赋值给指针; 操作野指针对应的空间可能会报错,操作空指针对应的空间一定会报错
---万能指针:void* 指针可以指向任意变量的内存空间
int aa = 10; void* po = &aa; *(int*)po = 100; printf("万能指针在内存占的字节大小: %d\n", sizeof(void*)); // 4 printf("po值为: %d\n", *(int*)po);
---const修饰的指针
---1. const修饰指针类型:可以修改指针变量的值,不可以修改指针指向内存空间的值
int a = 10, b = 20; const int* p = &a; printf("%d\n", *p); // 10 p = &b; printf("%d\n", *p); // 20
---2. const修饰指针变量:可以修改指针指向内存空间的值,不可以修改指针变量的值
int a = 10, b = 20; int* const p = &a; *p = 300; printf("%d\n", a); // 300
---3. const既修饰指针类型,又修饰指针变量(只读指针):p 中存放的内存单元的地址和内存单元中的内容都不可变
---指针的加法:指针与一个整数相加,整数都会和指针所指向类型的大小(以字节为单位)相乘,然后把结果与初始地址相加
int m, * n; n = &m; printf("n为:%d\n", n); // n为:11533100 n = n + 2; printf("n为:%d\n", n); // n为:11533108
---指针的减法
int m1, * n1; n1 = &m1; printf("n1为:%d\n", n1); // n为:16710620 n1 = n1 - 2; printf("n1为:%d\n", n1); // n为:16710612
---递增指针:用指针代替数组,因为变量指针可以递增,而数组不能递增,数组可以看成一个指针常量
int str[5] = { 100,200,300,400,500 }; int* ptr; ptr = &str[2]; printf("ptr = %p\n", ptr); // ptr = 010FF694 //指针递增 ptr++; printf("ptr = %p\n", ptr); // ptr = 010FF698
---递减指针:对指针进行递减运算,即把值减去其数据类型的字节数
int str[5] = { 100,200,300,400,500 }; int* ptrr; ptrr = &str[2]; printf("ptrr = %p\n", ptrr); // ptrr = 0133F6F8 //指针递减 ptrr--; printf("ptrr = %p\n", ptrr); // ptrr = 0133F6F4
---指针的比较:指针可以用关系运算符进行比较,如 ==、< 和 >;如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较
int str[5] = { 100,200,300,400,500 }; int *pt; pt = str; if (pt <= &str[4]) { printf("pt存储地址小于str[4]的存储地址\n"); // pt存储地址小于str[4]的存储地址 } else { printf("pt存储地址大于str[4]的存储地址\n"); }
---指针数组:指针数组是一个数组,其中的每个元素都是指向某种数据类型的指针
---指向字符的指针数组来存储一个字符串列表
const char* names[] = { "Zara Ali", "Hina Ali", "Nuha Ali", "Sara Ali", }; for (int i = 0; i < 4; i++) { printf("Value of names[%d] = %s\n", i, names[i]); // Value of names[0] = Zara Ali Value of names[1] = Hina Ali Value of names[2] = Nuha Ali Value of names[3] = Sara Ali }
---指针分别指向不同的整数变量 ,使用指针数组访问整数变量的值
int num1 = 10, num2 = 20, num3 = 30; // 声明一个整数指针数组,包含三个指针 int* ptrArray[3]; // 将指针指向不同的整数变量 ptrArray[0] = &num1; ptrArray[1] = &num2; ptrArray[2] = &num3; // 使用指针数组访问这些整数变量的值 printf("Value at index 0: %d\n", *ptrArray[0]); // Value at index 0: 10 printf("Value at index 1: %d\n", *ptrArray[1]); // Value at index 1: 20 printf("Value at index 2: %d\n", *ptrArray[2]); // Value at index 2: 30
---数组指针访问数组中的整数
int strNum[] = {100,200,300}; int* pr[3]; for (int i = 0; i < 3; i++) { pr[i] = &strNum[i]; printf("Value of var[%d] = %d\n", i, *pr[i]); // Value of var[0] = 100 Value of var[1] = 200 Value of var[2] = 300 }
---传递指针给函数
void getSeconds(unsigned long* par); void getSeconds(unsigned long* par) { *par = time(NULL); return; } int main() { unsigned long sec; getSeconds(&sec); printf("Number of seconds: %ld\n", sec); // Number of seconds: 1705564370 }
---数组指针作为参数
double getAverage(int* arr, int size); double getAverage(int* arr, int size) { double sum = 0.0; for (int i = 0; i < size; i++) { sum += arr[i]; } double avg = sum / size; return avg; } int main() { int balance[5] = {1000,2,3,17,50}; double avg = getAverage(balance, 5); printf("Average value is: %f\n", avg); // Average value is: 214.400000 }
---从函数返回指针:C 语言不支持在调用函数时返回局部变量的地址,除非定义局部变量为 static 变量
int* getRandom(); int* getRandom() { static int r[10]; int i; /* 设置种子 */ srand((unsigned)time(NULL)); for (i = 0; i < 10; ++i) { r[i] = rand(); printf("%d\n", r[i]); } return r; } int main() { int* pp; pp = getRandom(); for (int i = 0; i < 10; i++) { printf("*(pp + [%d]) : %d\n", i, *(pp + i)); } }
---值传递和地址传递
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; // 值传递 形参不影响实参的值 swap(a, b); printf("值传递 a的值为:%d\n", a); // 值传递 a的值为:10 printf("值传递 b的值为:%d\n", b); // 值传递 b的值为:20 // 地址传递 形参可以改变实参的值 swap1(&a, &b); printf("地址传递 a的值为:%d\n", a); // 地址传递 a的值为:20 printf("地址传递 b的值为:%d\n", b); // 地址传递 b的值为:10 return 0; }
---数组名作为函数参数
// 连接两个字符串 void pointerAs(char* ch1, char* ch2) { while (*ch1) ch1++; while (*ch2) { *ch1 = *ch2; ch1++; ch2++; } } int main() { char ch1[100] = "hello "; char ch2[] = "world"; pointerAs(ch1, ch2); printf("指针写法:%s\n", ch1); // hello world }
// 字符串去空格 void strRemoveSpace(char* ch) { char* fTemp = ch; char* rTemp = ch; while (*fTemp) { if (*fTemp != ' ') { *rTemp = *fTemp; rTemp++; } fTemp++; } *rTemp = 0; } int main() { char ch[] = " h e l l o w o r l d "; strRemoveSpace(ch); printf("字符串去除空格后为:%s\n", ch); // helloworld }
---指针作为函数返回值
// 查找字符串的某个字符 char* returnPointer(char* str, char ch) { while (*str) { if (*str == ch) { return str; } str++; } return NULL; } int main() { char str[] = "hello world"; char* p = returnPointer(str, 'd'); if (p == NULL) { printf("未找到\n"); } else { printf("%s\n",p); // d } return 0; }
// 在一个字符串中查找另一个字符串的位置 char* findStr(char* src, char* dest) { char* fsrc = src; // 循环遍历的指针 char* rsrc = src; // 记录想同的首地址 char* tdest = dest; while (*fsrc) { rsrc = fsrc; while (*fsrc == *tdest && *fsrc != '\0') { fsrc++; tdest++; } if (*tdest == '\0') { return rsrc; } // 回滚 fsrc = rsrc; tdest = dest; fsrc++; } return NULL; } int main() { char src[] = "llhello world"; char dest[] = "llo"; char* p = findStr(src, dest); printf("%s\n", p); // llo world return 0; }