C语言二维数组初始化和作形参时常见的坑

1、int二维数组初始化方式

int A[2][3] = {1, 2, 3, 4, 5, 6};
对应顺序是
A[0][0]=1; A[0][1]=2; A[0][2]=3;
A[1][0]=4; A[1][1]=5; A[1][2]=6;

int A[2][3] = {1, 2, 3, 4};
其中剩余的未赋值元素编译器自动初始化为0。
数组元素值对应顺序是
A[0][0]=1; A[0][1]=2; A[0][2]=3;
A[1][0]=4; A[1][1]=0; A[1][2]=0;

int A[2][3] = {{1, 2, 3}, {4}};
其中剩余的未赋值元素编译器自动初始化为0。
数组元素值对应顺序是
A[0][0]=1; A[0][1]=2; A[0][2]=3;
A[1][0]=4; A[1][1]=0; A[1][2]=0;

int A[][3] = {{1, 2, 3}, {4}};
省略行数,切记列数无法省略。其中剩余的未赋值元素编译器自动初始化为0。
数组元素值对应顺序是
A[0][0]=1; A[0][1]=2; A[0][2]=3;
A[1][0]=4; A[1][1]=0; A[1][2]=0;

2、char二维数组初始化方式

char A[2][3] = {'a', 'b', 'c', 'd'};
其中未初始化的部分,编译器自动初始为'0'NULL)。
printf("%s\n", A);
输出"abcd"

char A[2][3] =  {{'a'}, {'d', 'e', 'f'}};
其中未初始化的部分,编译器自动初始为'0'NULL)。
printf("%s\n", A);
输出"a",输出第一行时遇到结束符导致停止输出。

char A[2][3] = {{'a', 'b', 'c'}, {'d', 'e', 'f'}};
printf("%s\n", A);
输出"abcdef"
    
char A[][3] = {{'a', 'b'}, {'d'}};
省略行数,切记列数无法省略。
printf("%s\n", A);
输出"ab"

3、二维数组作为形参

想要在函数中传递一个一维数组作为参数,必须以下面三种方式来声明函数形式参数,这三种声明方式的结果是一样的,因为每种方式都会告诉编译器将要接收一个整型指针

方式1,形式参数是一个指针
void myFunction1(int *param)

方式2,形式参数是一个已定义大小的数组
void myFunction2(int param[10])

方式3,形式参数是一个未定义大小的数组
void myFunction3(int param[])

int param[3] = {0};
myFunction1(param);
myFunction2(param);
myFunction3(param);
int *param2;
myFunction1(param2);
myFunction2(param2);
myFunction3(param2);

就函数而言,一维数组作为形参时的长度是无关紧要的,因为 C 不会对形式参数执行边界检查。

同样的方式也可以传递一个多维数组作为形式参数?

方式1,形式参数是一个指针
void myFunction1(int **param)

方式2,形式参数是一个已定义大小的数组
void myFunction2(int param[2][10])
void myFunction2(int param[2][3])

方式3,形式参数是一个未定义一维宽度的数组
void myFunction3(int param[][3])

方式4
void myFunction4(int (*a)[3])

方式5
void myFunction5(int *a[3])

int param[2][3] = {0};
myFunction1(param);
错误,[Error] cannot convert 'int (*)[3]' to 'int**' for argument '1' to 'void myFunction(int**)'int param[2][3]中param其实是"int (*)[3]"类型,不是"int**"类型,这两者不能混用
myFunction2(param);
二维宽度为10的错误,[Error] cannot convert 'int (*)[3]' to 'int (*)[10]' for argument '1' to 'void myFunction2(int (*)[10])',可以理解为"int (*)[3]""int (*)[10]"不是一种类型
为3的正确,二维数组作为函数形参会进行边界检查,所以第二个维度必须一致
myFunction3(param);
myFunction4(param);
myFunction5(param);
错误,注意如果是int *a[3],因为"[]"的优先级比"*"高,所以会导致该形参被编译器识别为"int**"

int **param2 = (int **)malloc(sizeof(int *) * 2);
myFunction1(param);
myFunction2(param);
myFunction3(param);
myFunction4(param);
myFunction5(param);
只有myFunction1和myFunction5正确,其余的形参都不是"int**"类型
注意myFunction5中的"a[3]"类似一维数组作形参的效果,不管数组大小都被当作"int *"

4、综合例子

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 二维数组作为函数的形式参数会进行边界检查,所以第二个维度必须为5 
void example(char acHello[][5])
{
	printf("%d\n", sizeof(char (*)[5])); // 输出8
	printf("%d\n", sizeof(acHello)); // 输出8,为sizeof(char (*)[5]),指针为8 
	printf("%d\n", strlen(acHello[0])); // 输出9,因为acHello[0]并没有'\0'结束符,所以是acHello的总长度 
	acHello[0][0] = 'c';
	return;
}

int main(void)
{
	char str[] = "\\\\";
	printf("%d\n", sizeof(str)); // 输出3,\\其实是转义,所以2个'\'加字符串自带的1个'\0'是3 
	printf("%d\n", strlen(str)); // 输出2,即2个'\' 
	
	char *str2 = "\\\\";
	printf("%d\n", sizeof(str2)); // 输出8,str是char*类型的指针,指针在64位下都是8 
	printf("%d\n\n", strlen(str2)); // 输出2,即2个'\' 

	char str3[2][3] = {"qw", "er"};
	printf("%c ", *(*(str3 + 0) + 0));
	printf("%c ", *(*(str3 + 0) + 1));
	printf("%c ", *(*(str3 + 1) + 0));
	printf("%c\n", *(*(str3 + 1) + 1));

	printf("%c ", *(str3[0] + 0));
	printf("%c ", *(str3[0] + 1));
	printf("%c ", *(str3[1] + 0));
	printf("%c\n", *(str3[1] + 1));

	printf("%c ", str3[0][0]);
	printf("%c ", str3[0][1]);
	printf("%c ", str3[1][0]);
	printf("%c\n\n", str3[1][1]);
	// *(str3 + 0)等效于str3[0],*(*(str3 + 0) + 0)等效于str3[0][0] 

	char *szStr = "abcde";
	printf("%c\n", szStr[0]); // 输出a 
	printf("%llu\n", szStr); // 输出4210713,该值为"abcde"这个常串中字符a所在的地址
	szStr += 2;
	printf("%c\n", szStr[0]); // 输出c 
	printf("%llu\n\n", szStr); // 输出4210715,该值为"abcde"这个常串中字符c所在的地址

	char dqq[][10] = {{'h', 'e', 'l', 'l', 'o'}, {'q', 'w', 'e'}};
	printf("%s\n", dqq); // 输出hello,因为第一维多的部分被自动初始化为'\0',所以输出的时候截断了 
	printf("%s\n", dqq[1]); // 将第二维输出,所以是输出qwe
	printf("%c\n\n", dqq[1][0]); // 输出q

	char acHello[][5] = {{'h', 'e', 'l', 'l', 'o'}, {'h', 'e', 'l', 'l'}};
	example(acHello);
	printf("%s\n\n", acHello); // 输出cellohell,由于是传的指针,所以第一个字符被修改为c

	return 0;
}
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 愉快的开始-HELLO WORLD 14 1.1 INCLUDE头文件包含 14 1.2 MAIN函数 14 1.3 注释 14 1.4 {}括号,程序题和代码块 14 1.5 声明 14 1.6 C语言自定义名字的要求 15 1.7 PRINTF函数 15 1.8 RETURN语句 15 1.9 SYSTEM系统调用 15 1.9.1 System返回值在windows和unix下的不同, 15 1.9.2 POSIX 15 1.10 C语言编译过程,GCC参数简介 16 1.10.1 C语言编译过程 16 1.10.2 -E预编译 16 1.10.3 -S汇编 16 1.10.4 -c编译 16 1.10.5 链接 16 1.11 操系统结构 17 1.11.1 用户模式 17 1.11.2 内核模式 17 1.12 64位,32位系统区别 18 1.12.1 CPU内部结构与寄存器 18 1.12.2 RISC与CISC CPU构架 18 1.12.3 SPARC,x86与ARM 18 1.13 汇编语言 18 1.13.1 I386汇编简介 18 1.13.2 VS反汇编 19 1.14 IDE工具 19 1.14.1 QT常用快捷键 19 1.14.2 VS常用快捷键 19 1.14.3 VS断点,调试 19 2 C语言中的数据类型 19 2.1 常量 19 2.1.1 #define 19 2.1.2 const 19 2.2 字符串常量 20 2.3 二进制数、位、字节与字 20 2.4 八进制 20 2.5 十六进制 20 2.6 原码 21 2.7 反码 21 2.8 补码 21 2.9 SIZEOF关键字 22 2.10 INT类型 22 2.10.1 int常量,变量 22 2.10.2 printf输出int值 23 2.10.3 printf输出八进制和十六进制 23 2.10.4 short,long,long long,unsigned int 23 2.10.5 整数溢出 23 2.10.6 大端对齐与小端对齐 23 2.11 CHAR类型 24 2.11.1 char常量,变量 24 2.11.2 printf输出char 24 2.11.3 不可打印char转义符 24 2.11.4 char和unsigned char 25 2.12 浮点FLOAT,DOUBLE,LONG DOUBLE类型 25 2.12.1 浮点常量,变量 25 2.12.2 printf输出浮点数 25 2.13 类型限定 25 2.13.1 const 25 2.13.2 volatile 26 2.13.3 register 26 3 字符串格式化输出和输入 26 3.1 字符串在计算机内部的存储方式 26 3.2 PRINTF函数,PUTCHAR函数 27 3.3 SCANF函数与GETCHAR函数 28 4 运算符表达式和语句 29 4.1 基本运算符 29 4.1.1 = 29 4.1.2 + 29 4.1.3 – 29 4.1.4 * 29 4.1.5 / 29 4.1.6 % 29 4.1.7 += 29 4.1.8 -= 29 4.1.9 *= 29 4.1.10 /= 30 4.1.11 %= 30 4.1.12 ++ 30 4.1.13 -- 30 4.1.14 逗号运算符 30 4.1.15 运算符优先级 30 4.2 复合语句 31 4.3 空语句 31 4.4 类型转化 31 5 条件分支语句 31 5.1 关系运算符 31 5.1.1 < 31 5.1.2 <= 31 5.1.3 > 32 5.1.4 >= 32 5.1.5 == 32 5.1.6 != 32 5.2 关系运算符优先级 32 5.3 逻辑运算符 32 5.3.1 && 32 5.3.2 || 32 5.3.3 ! 33 5.4 IF 33 5.5 IF ELSE 34 5.6 IF ELSE IF 34 5.7 SWITCH与BREAK,DEFAULT 35 5.8 条件运算符? 36 5.9 GOTO语句与标号 36 6 循环语句 36 6.1 WHILE 36 6.2 CONTINUE 37 6.3 BREAK 37 6.4 DO WHILE 37 6.5 FOR 37 6.6 循环嵌套 37 7 数组 38 7.1 一维数组定义与使用 38 7.2 数组在内存的存储方式 38 7.3 一维数组初始化 38 7.4 二维数组定义与使用 39 7.5 二维数组初始化 39 8 字符串与字符数组 39 8.1 字符数组定义 39 8.2 字符数组初始化 39 8.3 字符数组使用 40 8.4 随机数产生函数RAND与SRAND 40 8.5 用SCANF输入字符串 40 8.6 字符串的结束标志 41 8.7 字符串处理函数 41 8.7.1 gets 41 8.7.2 fgets函数 41 8.7.3 puts函数 42 8.7.4 fputs函数 42 8.7.5 strlen,字符串长度 42 8.7.6 strcat,字符串追加 42 8.7.7 strncat,字符串有限追加 43 8.7.8 strcmp,字符串比较 43 8.7.9 strncmp,字符串有限比较 43 8.7.10 strcpy字符串拷贝 43 8.7.11 strncpy字符串有限拷贝 43 8.7.12 sprintf,格式化字符串 43 8.7.13 Sscanf函数 44 8.7.14 strchr查找字符 44 8.7.15 strstr查找子串 44 8.7.16 strtok分割字符串 44 8.7.17 atoi转化为int 45 8.7.18 atof转化为float 45 8.7.19 atol转化为long 45 9 函数 45 9.1 函数的原型和调用 45 9.2 函数的形参与实参 45 9.3 函数的返回类型与返回值 46 9.4 MAIN函数与EXIT函数与函数的RETURN语句 46 9.5 多个源代码文件程序的编译 47 9.5.1 头文件的使用 47 9.5.2 #include与#define的意义 47 9.5.3 #ifndef与#endif 47 9.6 函数的递归 48 9.6.1 递归的过程分析 48 9.6.2 递归的优点 52 9.6.3 递归的缺点 52 1 指针 52 1.1 指针 52 1.1.1 指针的概念 52 1.1.2 指针变量的定义 52 1.1.3 &取地址运算符 52 1.1.4 无类型指针 52 1.1.5 NULL 53 1.1.6 空指针与野指针 53 1.1.7 指针的兼容性 53 1.1.8 指向常量的指针指针常量 54 1.1.9 指针数组的关系 54 1.1.10 指针运算 54 1.1.11 通过指针使用数组元素 55 1.1.12 指针数组 55 1.1.13 指向指针指针(二级指针) 55 1.1.14 指向二维数组指针 57 1.1.15 指针变量做为函数的参数 57 1.1.16 一维数组为函数参数 57 1.1.17 二维数组为函数参数 58 1.1.18 const关键字保护数组内容 58 1.1.19 指针做为函数的返回值 58 1.1.20 指向函数的指针 59 1.1.21 把指向函数的指针做为函数的参数 60 1.1.22 memset,memcpy,memmove函数 61 1.1.23 指针小结 63 2 字符指针与字符串 64 2.1 指针和字符串 64 2.2 通过指针访问字符串数组 64 2.3 函数的参数为CHAR * 64 2.4 指针数组做为MAIN函数的形参 65 3 内存管理 65 3.1 用域 65 3.1.1 auto自动变量 65 3.1.2 register寄存器变量 65 3.1.3 代码块用域的静态变量 66 3.1.4 代码块用域外的静态变量 66 3.1.5 全局变量 66 3.1.6 外部变量与extern关键字 66 3.1.7 全局函数和静态函数 66 3.2 内存四区 66 3.2.1 代码区 67 3.2.2 静态区 67 3.2.3 栈区 67 3.2.4 栈溢出 68 3.2.5 堆区 68 3.3 堆的分配和释放 70 3.3.1 malloc 70 3.3.2 free 70 3.3.3 calloc: 70 3.3.4 realloc 71 4 结构体,联合体,枚举与TYPEDEF 71 4.1 结构体 71 4.1.1 定义结构体struct和初始化 71 4.1.2 访问结构体成员 71 4.1.3 结构体的内存对齐模式 72 4.1.4 指定结构体元素的位字段 72 4.1.5 结构数组 72 4.1.6 嵌套结构 73 4.1.7 结构体的赋值 73 4.1.8 指向结构体的指针 73 4.1.9 指向结构体数组指针 73 4.1.10 结构中的数组成员和指针成员 73 4.1.11 在堆中创建的结构体 74 4.1.12 将结构为函数参数 74 4.1.13 结构,还是指向结构的指针 74 4.2 联合体 75 4.3 枚举类型 75 4.3.1 枚举定义 75 4.3.2 默认值 76 4.4 TYPEDEF 76 4.5 通过TYPEDEF定义函数指针 76 5 文件操 77 5.1 FOPEN 77 5.2 二进制和文本模式的区别 77 5.3 FCLOSE 78 5.4 GETC和PUTC函数 78 5.5 EOF与FEOF函数文件结尾 78 5.6 FPRINTF,FSCANF,FGETS,FPUTS函数 78 5.7 STAT函数 78 5.8 FREAD和FWRITE函数 79 5.9 FREAD与FEOF 79 5.10 通过FWRITE将结构保存到二进制文件中 79 5.11 FSEEK函数 80 5.12 FTELL函数 80 5.13 FFLUSH函数 80 5.14 REMOVE函数 81 5.15 RENAME函数 81 6 基础数据结构与算法 82 6.1 什么是数据结构 82 6.2 什么是算法 82 6.3 排序 83 6.3.1 冒泡排序 83 6.3.2 选择排序 83 6.4 查找 83 6.4.1 顺序查找 83 6.4.2 二分查找 83 6.5 链表 84 6.5.1 单向链表定义 84 6.5.2 单向链表数据结构定义 85 6.5.3 单向链表的实现 85

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值