c 里面字符串其实是字符数组。不过,只是知道这个还是很难精确表述字符串以及字符串数组。

一般形式的操作是这样子的:

	char arr[ROW][LENGTH];
    char *ptr[ROW];

    for (int i = 0; i < ROW; ++i) {
        ptr[i] = arr[i];
    }

从理论上讲,char arr[row][col]char * ptr[row]完全是一个东西。

但是,在作为函数参数的时候,这是两种不同的类型。

对于 call_arr(arr) , 这里的形参要如何定义呢?
对于 call_ptr(ptr),这里的形参又是什么?

函数原型:

call_arr(int col,int row, char arr[row][col]);

call_ptr(int row, char * ptr[row]);

传入这两个参数(arr以及 ptr),函数会分别理解成不同类型的指针。

对于第一种,函数只认为这是一个二维的字符数组,不会把每个一维数组作为字符指针(也就是字符串)去处理。

对于第二种,函数会认为这是一个一维数组,每个元素是一个字符指针。

可能你会困惑,第一种难道不能定义成 call_arr(int row, char * arr[row]) 这样的形式吗?

  • 答案是不能。因为这样定义,在call_arr()函数内部,会认为 arr是一个一个字符指针数组。而你传的实际参数是arr, 这就造成了类型不匹配。
    编译也许会通过。但是在实际处理的时候,函数无法将arr当时一个一维指针数组,也就导致,不能在其中做指针的操作。比如:arr[i] = "hello world"; 这种操作就是不被允许的。因为函数认为 arr[i]是一个一维的字符数组。不能将一个字符串常量指针直接赋值给一个字符数组。

如果这时候使用 strncpy(arr[i], "hello world", strlen("hello world")); 当然是可以赋值成功的。不过这也许不是你程序想要的效果。

来看一下具体的示例:

void call(int row, int col, char arr[row][col]) {
    printf("call start=====\n");
    for (int i = 0; i < row; ++i) {
        printf("%s\t", arr[i]);
    }
    printf("\ncall end=======\n");
}


void prints(char *arr[], int row) {
    for (int i = 0; i < row; i++) {
        puts(arr[i]);
    }
}


int main(int argc, char *argv[]) {
    char arr[ROW][LENGTH];
    char *ptr[ROW];

    for (int i = 0; i < ROW; ++i) {
        // 必须要这一步,否则排序就比较麻烦
        ptr[i] = arr[i];
    }

    inputs(ptr, ROW);
    call(ROW, LENGTH, arr);
    prints(ptr, ROW);
    return 0;
}

从输出效果来看,二者没有任何的区别;从代码逻辑看,二者也没有区别。
如果是仅仅看上面示例中的 void prints(char *arr[], int row);void call(int row, int col, char arr[row][col]); 基本看不出这两种形式的参数有什么区别。

从输出效果来看,二者没有任何的区别;从代码逻辑看,二者也没有区别。

再深入一点点。

比如还有一个根据字符串长度对数组进行排序的函数:

void sort_by_length(char *arr[], int row) {
    for (int i = 0; i < row - 1; i++) {
        for (int j = 0; j < row - 1 - i; j++) {
            if (strlen(arr[j]) < strlen(arr[j + 1])) {
                char *tmp = arr[j];
                arr[j] = arr[j + 1]; 
                arr[j + 1] = tmp;  
            }
        }
    }
}

对于 sort_by_length() 能不能传入 arr这个实参呢?显然是不能的,原因就是之前说的,类型不匹配。arr被传入,会被理解成一个二维的字符数组;而传入ptr就可以。

如果非要给 sort_by_length() 传入实参arr程序会出现运行出错。

那么,如果写成下面这样呢?

sort(ROW,LENGTH, arr); // main 函数里面调用
// 函数实现 -- 错误示例蛤
void sort(int row, int col, char arr[row][col]) {
    for (int i = 0; i < row - 1; i++) {
        for (int j = 0; j < row - 1 - i; j++) {
            if (strlen(arr[j]) < strlen(arr[j + 1])) {
                char *tmp = arr[j];
                arr[j] = arr[j + 1]; // 编译报错,不能直接给一维数组赋值
                arr[j + 1] = tmp; // 编译报错,原因同上
            }
        }
    }
}

error: array type ‘char [col]’ is not assignable
报错提示就是上面这种。

报错原因还是之前说的,类型不匹配。如果传入二维数组,函数只会将其解析成二维数组,不会“智能”的转换成一维字符指针数组。

不完全示例:字符串数组作为实参以及形参的表示

其中的 s_gets(char *, int) 完全可以使用系统函数fgets()替代。

		// 对应字符数组,就必须使用 strcpy 这样的函数去赋值
		void abcd(int row, int col, char arr[row][col]) {
		    for (int i = 0; i < row - 1; i++) {
		        for (int j = 0; j < row - 1 - i; j++) {
		            if (strlen(arr[j]) < strlen(arr[j + 1])) {
		                char tmp[LENGTH];
		                strncpy(tmp, arr[j], strlen(arr[j]));
		                strncpy(arr[j], arr[j + 1], strlen(arr[j + 1]));
		                strncpy(arr[j + 1], tmp, strlen(tmp));
		            }
		        }
		    }
		}
		// strncpy 不会给字符数组后面加`\0`, 需要手动添加的
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐