23.7 指标与递增递减运算子
#include <stdio.h> int main() { int v[5]; int *p; for (p = v; p != &v[5]; p++) { *p = 0; } return 0; } #include <stdio.h> int main() { int v[5]; int *p = v; while (p != v+5) { // *p = v; p++; *p++ = 0; // *(p++) = 0 运算顺序由里到外 } return 0; }
24. 指标与字串
24.1 字串字面常数的特殊性
1 char strA[] = "test"; 2 char *strB = "test"; // 字串字面常数可隐性转型成字元指标 3 4 strA[0] = 'T'; // (O) 5 strB[0] = 'T'; // (X) 未定义行为 6 7 strA = "Test"; // (X) 编译失败 8 strB = "Test"; // (O) 9 10 // 如果宣告的是字元本阵列身,我可以改字元 但是我不能整串换掉 11 // 如果宣告定义的是指标本身,我不可以改内容,但是可以整串换掉
24.2 const修饰字
- 资料型别被const修饰的变数在 初始化 之外就不能在被赋值了
- 在C语言里可以看成是唯一的属性
1 int a = 3; // (O) 2 const int b = 5; // (O) 3 4 5 a = 4; // (O) 6 b = 6; // (X) 编译失败
24.3 字串字面常数与const char*
一般情况下,能够放双引号的地方,也就是放字串字面常数的地方,通常是const char* format的形式
24.4 指标与const
Type * 可以改成 const Type *
1 char strA[] = "test"; 2 char *strB = "test"; 3 const char *strC = "test"; 4 5 strA[0] = 'T'; // O 6 strB[0] = 'T'; // X (未定义行为) 我们一般不用这种情况 尽量避免这种情况 对程序有隐患 7 8 strC[0] = 'T'; // X (编译失败) 9 10 // 要么选择A 要么就是C 11 12 strA = strB; // (char []) = (char *) (X) 13 strA = strC; // (char []) = (const char *) (X) 14 15 strB = strA; // (char *) = (char []) (O) 16 strB = strC; // (char *) = (const char *) (X) 17 18 strC = strA; // (const char *) = (char []) (O) 19 strC = strB; // (const char *) = (char *) (O)
24.5 使用函式复制字串
1 #include <stdio.h> 2 #include <string.h> 3 4 int main() { 5 char source[5] = "test"; 6 char destination[5]; 7 8 // 深复制(deep copy) 9 int i; 10 for (i = 0; i < 5; i++) { 11 destination[i] = source[i]; 12 } 13 printf("%s ", destination); 14 return 0; 15 }
1 #include <stdio.h> 2 #include <string.h> 3 4 int main() { 5 char source[5] = "test"; 6 char destination[5]; 7 8 strcpy(destination, source); 9 10 printf("%s ", destination); 11 return 0; 12 } 13 14 15 test 16 17 Process returned 0 (0x0) execution time : 0.920 s 18 Press any key to continue.
25.1 指标阵列
1 #include <stdio.h> 2 // 指标阵列初始化 3 int main() 4 { 5 int v[3] = {1, 2, 3}; 6 7 int *p[3] = {&v[2], &v[1], &v[0]}; 8 9 // 循序存取 10 int i; 11 for (i = 0; i < 3; i++) { 12 *p[i] = 0; 13 } 14 // 随机存取 15 *p[2] = 5; 16 return 0; 17 } 18 19 int a[4] = {1, 2, 7, 8}; 20 int b[2] = {3, 4}; 21 int c[2] = {5, 6}; 22 23 int *p[3] = {a, b, c}; 24 25 // 循序存取 26 int i; 27 for (i = 0; i < 3; i++) { 28 for (j = 0; j < 2; j++) { 29 p[i][j] = 0; 30 } 31 } 32 33 // 随机存取 34 p[0][2] = 9; 35 p[1][2] = 10; // (X) 未定义行为 超出阵列范围 36 37 38 // 指向阵列第一个元素的指标 39 40 int v[3] = {1, 2, 3}; 41 42 int *n = v; 43 44 // 循序存取 45 int i; 46 for (i = 0; i < 3; i++) { 47 n[i] = 0; 48 49 } 50 51 // 随机存取 52 n[2] = 5;
25.2 阵列的指标
// 在函式间传递固定大小的阵列 // 第一种 #include <stdio.h> void print(int (*q)[3]) { int i; for (i = 0; i < 3; i++) { printf("%d ", (*q)[i]); } printf(" "); } int main() { int v[3] = {1, 2, 3}; print(&v); return 0; } //第二种 经常使用的 #include <stdio.h> void print(int *n) { int i; for (i = 0; i < 3; i++) { printf("%d ", n[i]); } printf(" "); } int main() { int v[3] = {1, 2, 3}; print(v); return 0; }
这两者各有优缺点
#include <stdio.h> void print(int (*q)[3]) { // 5 int i; for (i = 0; i < sizeof(*q)/sizeof((*q)[0]); i++) { printf(" %d", (*q)[i]); } printf(" "); } int main() { int v[] = {1, 2, 3}; // 5 print(&v); return 0; } // 缺点就是不可以同时传不同的大小阵列 #include <stdio.h> void print(int *n) { int i; for (i = 0; i < sizeof(n)/sizeof(n[0]); i++) { printf("%d ", n[i]); } printf(" "); } int main() { int v[3] = {1, 2, 3}; print(v); return 0; } // 失去了长度的概念 #include <stdio.h> void print(int *n, int size) { int i; for (i = 0; i < size; i++) { printf("%d ", n[i]); } printf(" "); } int main() { int v[3] = {1, 2, 3}; print(v, 3); int b[5] = {7, 8, 9}; print(b, 5); return 0; }
26.1 指标间转型的限制
绝大部分情况下,指向不同型别的指标间是不能直接隐性转型的
合法的隐性转型
- 同型别内互转
- 整数与浮点数
- 阵列可以隐性转型成指向第一个元素的指标,反过来不行、
- Type * 可以隐性转型成 const Type * 反过来也不行
- void * 与其他型别的指标 可能 可以互转
1 include <stdio.h> 2 3 int main() { 4 5 int intVar = 3; 6 7 void *voidPtr = &intVar; 8 9 double *doublePtr = voidPtr; 10 11 printf("%f ", *doublePtr); 12 13 return 0; 14 }