C语言犄角旮旯的知识之数组与函数

简介: C语言犄角旮旯的知识之数组与函数

目录


数组

不存在的数组

数组的地址

字符型数组

函数

函数的注释

函数与数组

一二维数组做函数的形参与实参


正文


数组


首先单独讲一下数组


不存在的数组


数组实在是太奇妙了,有些老师会介绍说,数组有一维数组、二维数组、三维数组······,也有些老师会说数组其实只有一维的,其他都是一维数组的嵌套。而笔者认为,C语言中重来没有数组,只有指针,或者说数据地址(虽然这么说优点无赖的感觉)。举个例子,对于int a[2];中a[1]来说,大部分老师会怎么解释呢,没错,老师都会说这是a数组里的第二个元素,但是你可以去尝试输出printf("%d\n",1[a]);,会有什么情况呢,会报错吗,答案是不会,而且完全正确!!就连你输出的值与a[1]也别无二般,但你总不能说这是一个数组名叫“2”的数组中第二个元素吧。这其中到底有什么玄关呢,笔者先买个关子,等在数组与指针那一篇里面再详细解读。


我们先来看看数组的其他知识


数组的地址


当我们定义一个数组时,数组的首地址就已经确定,且不能更改,如  int a[10];  这个数组的首地址就是a,而数组的下标则是对a地址的偏移量。一个数组的地址是连续的。随意更改数组首地址将会报错。


字符型数组


这里有三个字符型数组要注意的点


当说一个数组的长度时,说的就是这个数组的元素个数,但如果是字符型的数组,最后会加上一个“/0"字符(只会在字符串后面自动加,其他的如char a[] = {'a','b'}是不会加的,用sizeof和strlen求都是2)。使用sizeof求长度时,会计入这个字符,长度加一,使用strlen求长度时,不会计入。


根据以上,请问以下两个定义是否有错

char a[5] = {"abcde"};
char a[5] = {'a','b','c','d','e'};

答案是第一个是错的,第二个是正确的。为什么呢,因为字符串后面会自动加一个字符'/0',所以第一个定义实际上有6个字符,超出数组大小,而第二个定义不会加'/0',所以还是5个字符。


当有  char a[] = {0,1,48};的字符型数组被定义时,初始化中,像这样直接写的是数字的,其实记录的是对应字符的ASCII码值,如a[2]其实是ASCII为‘48’的那个字符。想要存储字符,就必须有单引号引起来。


我们再看一组就能更加深入理解sizeof与strlen这两个关键字了

char s[6]={'2','3','\0','6','5'} ;
printf("%d\n",sizeof(s));        //输出 “2”
char s[6]={'2','3','\0','6','5'} ;
printf("%d\n",strlen(s));        //输出  “6”
char s[6]={'2','3','\0','6','5','8'} ;
printf("%d\n",sizeof(s));        //输出  “6”

可以看出,sizeof会在数组未满时,或者字符串后面自动计数上“/0”结束符,并且不会因为中间遇到“/0”结束符就中止计数,会将所有元素个数计入;而strlen会遇上“/0”就会中止计数,并不计入“/0”结束符。


连续定义数组空间分配问题


两个或多个数组连续定义的时,一般会连续分配空间,不止是数组,当我们连续定义变量时,大概率都会连续分配空间,而当我们不注意空间大小时,可能数据会溢出到其他变量里。

让我们判断一下一下程序会输出上面呢?

char s1[8];
char s2[8] = {"abcde"};
strcpy(s1,"0123456789");    //strcpy:将后面的字符串复制到前面的变量里
printf("%s\n",s1);
printf("%s\n",s2);

答案是:

0123456789
89

因为s1与s2的内存分布是连着的,而strcpy不会考虑是否越界,所以字符“89”将越界到s2中去,这也导致s1中没有了结束符,所以会一直读到有结束符的地方,再strcpy完后,也自动加上“/0‘结束符,也就是s2[8] = {'8',9','\0','d','e'}。(当然,有些编译器可以不会出现这种问题)


函数


函数的注释


初学者可能还没有深刻的认识,但已经从事开发的程序员来说,这一点是非常重要的一点。毕竟程序员都讨厌两种人,一种是不写注释的人,还有一种就是让自己写注释的人。很荣幸,我也成了其中之一。所以就让我们在现在做起,做一个会写注释的好程序员吧。


对于语句的注释,那当然就是表达清晰即可,但对于函数的注释,是要很规范的,这样,别人看你的代码和你看别人的代码都能节约不少时间,格式如下:

/*函数名:函数功能
    @:形参名1:形参名1的含义
    @:形参名2:形参名2的含义
    ...
    @:形参名n:形参名n的含义
    返回值:
        返回值1:返回值1的含义
        返回值n:返回值n的含义
        ...
        返回值n:返回值n的含义
*/

这里涉及到了形参,其实对应的还有一个实参,他们的区别是:

形式参数:定义函数时,指定的参数

实际参数:调用函数时,指定的参数


函数与数组


一二维数组做函数的形参与实参


一维数组做函数的形参与实参

int a[10];
void function(int a[],int n)  //形式参数
function(a,10)  //实际参数

一维数组做函数的形参与实参

int a[5][10];
void function(int a[][10],int n)  //形式参数
function(a,5)  //实际参数

到这里,数组与指针的关系就介绍完啦,如果对你有帮助的话,可以点个赞收藏一下哦。后续这个专栏也会出指针与数组和函数的相关文章,相信我,那个才是真的有趣!!


相关文章
|
8天前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
32 4
|
15天前
|
C语言
c语言调用的函数的声明
被调用的函数的声明: 一个函数调用另一个函数需具备的条件: 首先被调用的函数必须是已经存在的函数,即头文件中存在或已经定义过; 如果使用库函数,一般应该在本文件开头用#include命令将调用有关库函数时在所需要用到的信息“包含”到本文件中。.h文件是头文件所用的后缀。 如果使用用户自己定义的函数,而且该函数与使用它的函数在同一个文件中,一般还应该在主调函数中对被调用的函数做声明。 如果被调用的函数定义出现在主调函数之前可以不必声明。 如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调函数中不必多所调用的函数在做声明
30 6
|
1月前
|
存储 缓存 C语言
【c语言】简单的算术操作符、输入输出函数
本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
40 10
|
28天前
|
存储 算法 程序员
C语言:库函数
C语言的库函数是预定义的函数,用于执行常见的编程任务,如输入输出、字符串处理、数学运算等。使用库函数可以简化编程工作,提高开发效率。C标准库提供了丰富的函数,满足各种需求。
|
1月前
|
机器学习/深度学习 C语言
【c语言】一篇文章搞懂函数递归
本文详细介绍了函数递归的概念、思想及其限制条件,并通过求阶乘、打印整数每一位和求斐波那契数等实例,展示了递归的应用。递归的核心在于将大问题分解为小问题,但需注意递归可能导致效率低下和栈溢出的问题。文章最后总结了递归的优缺点,提醒读者在实际编程中合理使用递归。
61 7
|
1月前
|
存储 编译器 程序员
【c语言】函数
本文介绍了C语言中函数的基本概念,包括库函数和自定义函数的定义、使用及示例。库函数如`printf`和`scanf`,通过包含相应的头文件即可使用。自定义函数需指定返回类型、函数名、形式参数等。文中还探讨了函数的调用、形参与实参的区别、return语句的用法、函数嵌套调用、链式访问以及static关键字对变量和函数的影响,强调了static如何改变变量的生命周期和作用域,以及函数的可见性。
30 4
|
1月前
|
存储 编译器 C语言
【c语言】数组
本文介绍了数组的基本概念及一维和二维数组的创建、初始化、使用方法及其在内存中的存储形式。一维数组通过下标访问元素,支持初始化和动态输入输出。二维数组则通过行和列的下标访问元素,同样支持初始化和动态输入输出。此外,还简要介绍了C99标准中的变长数组,允许在运行时根据变量创建数组,但不能初始化。
38 6
|
1月前
|
存储 C语言
【c语言】字符串函数和内存函数
本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
25 0
|
1月前
|
C语言
【c语言】qsort函数及泛型冒泡排序的模拟实现
本文介绍了C语言中的`qsort`函数及其背后的回调函数概念。`qsort`函数用于对任意类型的数据进行排序,其核心在于通过函数指针调用用户自定义的比较函数。文章还详细讲解了如何实现一个泛型冒泡排序,包括比较函数、交换函数和排序函数的编写,并展示了完整的代码示例。最后,通过实际运行验证了排序的正确性,展示了泛型编程的优势。
21 0
|
1月前
|
算法 C语言
factorial函数c语言
C语言中实现阶乘函数提供了直接循环和递归两种思路,各有优劣。循环实现更适用于大规模数值,避免了栈溢出风险;而递归实现则在代码简洁度上占优,但需警惕深度递归带来的潜在问题。在实际开发中,根据具体需求与环境选择合适的实现方式至关重要。
28 0