1 数组的特例:字符串
在C语言中,定义一个字符串样式的数组,有如下两种方式:
char arr[] = "abcdefg";
char *str = "abcdefg";
这两种方式有什么区别呢?别看它们表面上都差不多,其实差远了!
1.1 字符数组定义字符串——从一而终
这里的数组名 arr:实际上是个变种的“指针常量”,
(1)常量说明了“绑定关系”不能变,这种定义字符串的方式,会在栈帧里面存放“abcdefg\0”这一个字符数组实体,arr 在函数体的整个生命周期里面不能再绑定其他的东西!直到这个函数体的消亡,一起被销毁;
(2)“变种”有3个含义:
① 共享房子的大小:arr的大小,将等于"abcdefg\0"的大小
② 共享房子的位置:arr的地址,将等于战阵中"abcdefg\0"的首地址
③ 相敬如宾:arr这个指针不能随便去"abcdefg\0"里面随便乱指,只能通过arr[0],arr[1]……这种固定的方式去访问“abcdefg\0”中的内容
1.2 字符指针定义字符串——登徒浪子
这里的指针 char *str:是一个指针变量,它就是一个登徒浪子!
(1)变量说明了“绑定关系”可以随时变!str在整个函数体的生命周期中,不一定非要绑定"abcdefg\0"这一个字符串常量,看它不顺眼了,可以改!
(2)“登徒浪子”是相对独立自主的!
① str 拥有自己独立的大小(就是指针的大小,与机器字长有关),而与字符串常量"abcdefg\0"的大小无关;
② str 拥有自己独立的地址,在栈帧之中占据一席地位,独立地分配了栈帧中的字节!
③ str 特别喜欢指指点点,可以使用str++, str–这样的方式,在 “abcdefg\0” 里面指来指去!
1.3 测试代码
#include <stdio.h>
int main(int argc, char *argv[]){
char arr[] = "abcdefh";
char *str = "abcdefh";
printf("argv = 0x%x\r\n", &argv);
printf("argc = 0x%x\r\n", &argc);
printf("adress of arr = 0x%x\r\n", &arr);
printf("adress of char *str = 0x%x\r\n", &str);
printf("adress of arr[0] = 0x%x\r\n", &arr[0]);
printf("adress of str[0] = 0x%x\r\n", &str[0]);
printf("adress of str[1] = 0x%x\r\n", &str[1]);
printf("arr[1] = \'%c\'\r\n", *(arr + 1));
printf("arr[0] = \'%c\'\r\n", *arr);
printf("*str++ = \'%c\'\r\n", *str++);
printf("now, \"str\" points to = \'%c\'\r\n", *str);
printf("str-- = \'%c\'\r\n", *str--);
printf("now, \"str\" points to \'%c\'\r\n", *str);
return 0;
}
1.4 栈帧结构
2 数组
类型 | 说明 |
---|---|
静态数组 | 数组的大小不能变 |
动态数组 | 数组的大小可以动态改变 |
2.1 静态数组
2.1.1 数组测试代码
#include <stdio.h>
int main(int argc, char *argv[]){
int i = 10;
int j = 20;
int array[4] = {
1, 2, 3, 4
};
int *p = array;
printf("argv = 0x%x\r\n", &argv);
printf("argc = 0x%x\r\n", &argc);
printf("int variable address = 0x%x\r\n", &i);
printf("int variable address = 0x%x\r\n", &j);
printf("array 0 address = 0x%x\r\n", &array[0]);
printf("array 1 address = 0x%x\r\n", &array[1]);
printf("array 2 address = 0x%x\r\n", &array[2]);
printf("array 3 address = 0x%x\r\n", &array[3]);
printf("pointer address = 0x%x\r\n", &p);
printf("int size %d", sizeof(int));
return 0;
}
2.1.2 栈帧结构
2.2 动态数组
C99 以上是支持“动态数组”的,可以使用如下语句:
int arr[i];
这个 i 是个变量,C99以下,不能这样玩,需要使用 malloc() 手动实现动态数组,使用 realloc() 可以对数组长度动态地进行调整,实现方法如下:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define ARR_SIZE 8
int main(int argc, char *argv[]){
int *dynamic_arr = (int *)malloc(ARR_SIZE * sizeof(int)); // Creating a dynamic array
assert(dynamic_arr != NULL);
for(int i = 0; i < ARR_SIZE; i ++){ // Printing the dynamic array
printf("dynamic_arr[%d] = %d \r\n", i, dynamic_arr[i]);
}
for(int i = 0; i < ARR_SIZE; i++){ // Initializing the dynamic array
dynamic_arr[i] = 0;
}
for(int i = 0; i < ARR_SIZE; i ++){ // Printing the dynamic array
printf("dynamic_arr[%d] = %d \r\n", i, dynamic_arr[i]);
}
/******** Adjusting the length of the dynamic array ********/
dynamic_arr = (int *)realloc(dynamic_arr, 16 * sizeof(int));
for(int i = 0; i < 16; i ++){ // Printing the new dynamic array
printf("dynamic_arr[%d] = %d \r\n", i, dynamic_arr[i]);
}
free(dynamic_arr); // Destroy the dynamic array
return 0;
}
3 指针数组和数组指针
注意:“各种括号” 的优先级比 “*” 高!
类别 | 示例 | 说明 | 应用 |
---|---|---|---|
指针数组 | char * s t r [ 8 ] \color{red}str[8] str[8] | 下标[8] 先结合,是数组,数组里每个单元放一个指针 | 函数入参,接收“字符串数组” |
数组指针 | int ( ∗ p A r r \color{red}*pArr ∗pArr)[4] | 括号() 先结合,是指针,指针指向一个int a[4] 样式数组 | 函数入参,接收“二维数组” |
3.1 用数组指针接收“二维数组”
int print_2Array(int (*pArr)[4], int len){
for(int i = 0; i < len; i++){
for(int j = 0; j < 4; j++){
printf("|%-4d", pArr[i][j]);
}
printf("|\r\n");
}
}
3.2 用二级指针接收“指针数组”
int print_strings(char **str, int len){
for(int i = 0; i < len; i++){
printf("|%-16s|\r\n", str[i]); // 1-level deference
}
}
3.3 测试例程
#include <stdio.h>
int main(int argc, char *argv[]){
char *str[8] = {
"Alice",
"Danny",
"Jenny",
"Red",
"Xiaoming",
"Alex",
"Angel",
"Jack"
};
int arr[6][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 0, 1, 2},
{3, 4, 5, 6},
{7, 8, 9, 0},
{1, 2, 3, 4},
};
int (*pArr)[4] = arr;
print_strings(str, sizeof(str) / sizeof(void *));
print_2Array(pArr, sizeof(arr) / sizeof(arr[0]));
printf("size of [arr] is %d bytes\r\n", sizeof(arr));
printf("size of [pArr] is %d bytes\r\n", sizeof(pArr));
return 0;
}