c语言知识点6
C 函数
函数是一组一起执行一个任务的语句。每个 C 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数。
定义函数
C 语言中的函数定义的一般形式如下:
return_type function_name( parameter list )
{
body of the function
}
返回类型:一个函数可以返回一个值。return_type 是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type 是关键字 void。
函数名称:这是函数的实际名称。函数名和参数列表一起构成了函数签名。
参数:参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
函数主体:函数主体包含一组定义函数执行任务的语句。
函数声明
函数声明会告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义。
return_type function_name( parameter list );
根据函数能否被其他源文件调用,将函数区分为内部函数和外部函数。
内部函数 如果一个函数只能被本文件中其他函数所调用,它称为内部函数。在定义内部函数时,在函数名和函数类型的前面加 static,即 static 类型名 函数名 (形参表)例如,函数的首行: static int max(int a,int b)内部函数又称静态函数。使用内部函数,可以使函数的作用域只局限于所在文件。即使在不同的文件中有同名的内部函数,也互不干扰。提高了程序的可靠性。
外部函数 如果在定义函数时,在函数的首部的最左端加关键字 extern,则此函数是外部函数,可供其它文件调用。 如函数首部可以为 extern int max (int a,int b)C 语言规定,如果在定义函数时省略 extern,则默认为外部函数。 在需要调用此函数的其他文件中,需要对此函数作声明(不要忘记,即使在本文件中调用一个函数,也要用函数原型来声明)。在对此函数作声明时,要加关键字 extern,表示该函数是在其他文件中定义的外部函数。 实例 以下实例通过多个文件的函数实现输入一串字符串,然后删除指定的字符:file1.c(文件1)
#include <stdio.h>
static void delete_string(char str[],char ch);
int main()
{
extern void enter(char str[]); // 对函数的声明
extern void print(char str[]); // 对函数的声明
char c,str[100];
enter(str);
scanf("%c",&c);
delete_string(str,c);
print(str);
return 0;
}
static void delete_string(char str[],char ch)//内部函数
{
int i,j;
for(i=j=0;str[i]!='\0';i++)
if(str[i]!=ch)
str[j++]=str[i];
str[j]='\0';
}
file2.c(文件2)
#include <stdio.h>
void enter(char str[100]) // 定义外部函数 enter
{
fgets(str, 100, stdin); // 向字符数组输入字符串
}
file3.c(文件3)
#include <stdio.h>
void print(char str[]) // 定义外部函数 print
{
printf("%s\n",str);
}
输入字符串"abcdef",给字符数组 str,在输入要删去的字符’d’。
运行结果:
abcdef // 输入的字符串
d //要删除的字符
abcef //删除后的字符串
内联函数
内联函数是指用inline关键字修饰的函数。在类内定义的函数被默认成内联函数。内联函数从源代码层看,有函数的结构,而在编译后,却不具备函数的性质。内联扩展是用来消除函数调用时的时间开销。它通常用于频繁执行的函数,对于小内存空间的函数非常受益。使用内联函数的时候要注意:递归函数不能定义为内联函数内联函数一般适合于不存在while和switch等复杂的结构且只有1~5条语句的小函数上,否则编译系统将该函数视为普通函数。内联函数只能先定义后使用,否则编译系统也会把它认为是普通函数。对内联函数不能进行异常的接口声明。示例:一个简单的交换函数
inline void swap(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
C 作用域规则
任何一种编程中,作用域是程序中定义的变量所存在的区域,超过该区域变量就不能被访问。C 语言中有三个地方可以声明变量:
- 在函数或块内部的局部变量
- 在所有函数外部的全局变量
- 在形式参数的函数参数定义中
实参可以是变量,变量与表达式。实参与形参。实参与形参类型相同或赋值兼容在调用函数过程中发生的实参与形参之间的数据传递,常称为“虚实结合”在定义函数中制定的形参,在没有出现函数调用时不占用内存中的存储单元。在函数调用时才分配内存将实参的值传递给形参在执行函数时,由于形参已经有值。可以用形参进行运算。通过return语句将函数值返回,若无返回值,则无return调用结束后,形参被释放掉,实参保留原值(单向传值)
C 数组
C 语言支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。
声明数组
在 C 中要声明一个数组,需要指定元素的类型和元素的数量,如下所示:
type arrayName [ arraySize ];
初始化数组
在 C 中,您可以逐个初始化数组,也可以使用一个初始化语句,如下所示:
double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};
对于数组的初始化需要注意以下几点:
- 可以只给部分元素赋值,当 { } 中值的个数少于元素个数时,只给前面部分元素赋值。例如:
int a[10]={12, 19, 22 , 993, 344};
表示只给 a[0]~a[4] 5 个元素赋值,而后面 5 个元素自动初始化为 0。
当赋值的元素少于数组总体元素的时候,不同类型剩余的元素自动初始化值说明如下:
对于 short、int、long,就是整数 0;
对于 char,就是字符 ‘\0’;
对于 float、double,就是小数 0.0。
我们可以通过下面的形式将数组的所有元素初始化为 0:
int nums[10] = {0};
char str[10] = {0};
float scores[10] = {0.0};
由于剩余的元素会自动初始化为 0,所以只需要给第 0 个元素赋值为 0 即可。 - 只能给元素逐个赋值,不能给数组整体赋值。例如给 10 个元素全部赋值为 1,只能写作:
int a[10] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
而不能写作:
int a[10] = 1;//当然编译都通不过哈哈哈
#include <stdio.h>
int main ()
{
int n[ 10 ]; /* n 是一个包含 10 个整数的数组 */
int i,j;
/* 初始化数组元素 */
for ( i = 0; i < 10; i++ )
{
n[ i ] = i + 100; /* 设置元素 i 为 i + 100 */
}
/* 输出数组中每个元素的值 */
for (j = 0; j < 10; j++ )
{
printf("Element[%d] = %d\n", j, n[j] );
}
return 0;
}
运行结果如下:
Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109
一个小知识点:
在我们没有明确数组的元素个数时,在程序中想知道数组单元个数可以使用 sizeof(a)/sizeof(a[0]), sizeof(a) 是得到数组 a 的大小,sizeof(a[0]) 是得到数组 a 中单个元素的大小(因此可以不必要是a[0],a[i]都行:
#include<stdio.h>
int main(int argc,char *args[])
{
int a[]={1,2,3,4,5};
int b;
b=sizeof(a)/sizeof(a[0]);
printf("数组元素个数为:%d",b);
return 0;
}
#include <stdio.h>
int main(int argc,char *args[])
{
int a[2] = {1,2};
printf("a = %d\n",a[0]);
printf("*(a+0) = %d\n",*(a + 0));
printf("a[1] = %d\n",a[1]);
printf("*a = %d\n",*a);
printf("*(a+1) = %d\n",*(a + 1));
printf("\n");
printf("a 的地址:%p\n",a);
printf("(a+0)的地址:%p\n",(a + 0));
printf("(a+1)的地址:%p\n",(a + 1));
// %p 读入一个指针
printf("\n");
return 0;
}
输出结果:
a = 1
*(a+0) = 1
a[1] = 2
*a = 1
*(a+1) = 2
a 的地址:0x7ffe9e227634
(a+0)的地址:0x7ffe9e227634
(a+1)的地址:0x7ffe9e227638
解释:
事实上 a[0] 、a[1]…a[i] 代表的都是值,a、(a+0)、(a+1)、(a+i) 代表的是地址;另外这里的 a
代表整个数组的首地址,相当于 a[0] 的地址,而这里 (a+1) 就代表的是 a[0+1] 的地址。
正如文章中提到的:所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素,即是说 (a+i) 就代表的是
a[0+i] 的地址。
数组变量是特殊的指针,数组变量本身表达地址,int a[10]; int *p =a;
数组变量无需用取址符& ;
数组的元素表达的是变量,需要用&取地址,如 m = &a[0];
[]运算符可以对数组做,也可以对指针做 p[0] == a[0];
*运算符可以对指针做,也可以对数组做 *a = 25, *a可以得到或者修改数组首个元素的值;
实际上数组是 const 的指针,所以不能被赋值。 如果 int a[] = {1,2,5,7}; int b[],由于 int b[]实质上等 价于 <===> int const *b; b 是一个常数,不能被改变,初始化出来代表这个数组就不能再改变。 b = a; (错误) 数组变量之间是不可以这样互相赋值的。 而 int *q = a; 这样是可以的。
C enum(枚举)
枚举是 C 语言中的一种基本数据类型,它可以让数据更简洁,更易读。
枚举语法定义格式为:
enum 枚举名 {枚举元素1,枚举元素2,……};
注意:第一个枚举成员的默认值为整型的 0,后续枚举成员的值在前一个成员上加 1。我们在这个实例中把第一个枚举成员的值定义为 1,第二个就为 2,以此类推。
枚举变量的定义
1、先定义枚举类型,再定义枚举变量
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
enum DAY day;
2、定义枚举类型的同时定义枚举变量
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
3、省略枚举名称,直接定义枚举变量
enum
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
关于枚举元素遍历问题的个人理解:
首先有个前提:定义的枚举元素从第二个元素开始,每个元素的值是在前一个元素的值得基础上加 1。
以下为一般情况,即 for 循环每次增加固定值(每次加 1 或者加 2…)
当你定义的元素是在 0 的基础上进行自增,那么采用 for 循环遍历时,则刚好能够正确遍历全部元素。因为此时 for 循环中用来自增判断的枚举变量的值能够与定义的元素值对应上,假设你定义了 7 个元素,并且第一个元素的值为 0,剩下 6 个元素没有另外再赋值或者按自增进行赋值,那么 day=0 时,输出的第一个枚举元素也是 0,day=6 时,输出为 6,刚好输出全部元素。
#include<stdio.h>
enum {
MON=0,TUE,WED,THU,FRI,SAT,SUN
} day;
int main(int argc,char *args[])
{
for(day=0;day<SUN;day++)
{
printf("枚举元素:%d \n",day); //实际上输出的是day这个变量的值,并不是所定义的枚举元素
}
}
当你定义的元素不是连续自增时,假设你定义了 7 个元素,第一个元素为 0,第 3 个元素为 5,那么你采用 for 循环遍历,输出的值不等于你定义的 7 个元素的值。因为 for 循环每次是增加固定值(假设每次增加 1),那么当 day=2 时,定义的第三个元素为 5,但是此时输出的是 day 这个变量的值 3,并不是所定义的第三个元素。
#include<stdio.h>
enum {
MON=0,TUE,WED=5,THU,FRI,SAT,SUN
} day;
int main(int argc,char *argv[])
{
for(day=0;day<SUN;day++)
{
printf("枚举元素:%d \n",day) ; //实际上输出的是day这个变量的值,并不是所定义的枚举元素
}
}