目录
一维字符型数组做函数参数
一维字符型数组主要用来存放字符串:从字符串角度入手时,我们不关心数组多长,而关系的是什么时候遇到停止标志'\0',所以字符型数组作为参数时,不用传入数组的长度。
//以下是从字符操作本质的形式重写了关于字符串操作的一些函数
//获取字符串并存储到s中(gets)
void Gets(char s[])
{
int i = 0;
//键盘没有按下回车前,一直获取字符并计数,定位应该加结束标志的下标
while ((s[i] = getchar()) != '\n')
{
i++;
}
//在结束位置添加结束标志
s[i] = '\0';
return;
}
//输出字符串(puts)
void Puts(char s[])
{
int i = 0;
//在没有遇到停止标志前,逐个打印出数组中的字符
while (s[i] != '\0')
{
printf("%c",s[i]);
i++;
}
//打印完成自动换行
printf("\n");
return;
}
//计算字符串的长度
int Strlen(char s[])
{
int len = 0;
//在没有遇见停止标志前,一直计数
while (s[len] != '\0')
{
len++;
}
//返回长度
return len;
}
//将源字符串复制到目标字符串(strcpy)
void Strcpy(char dest[],char src[])
{
int i = 0;
//在源字符串没有遇到停止标志前,逐次将源字符数组中的值赋值给目标数组
while (src[i] != '\0')
{
dest[i] = src[i];
}
//在复制完成后再结尾添加停止标志保证目标字符数组构成字符串
dest[i] = '\0';
return;
}
//将源字符串拼接到目标字符串的后面(strcat)
void Strcat(char dest[],char src[])
{
int i = 0;
int j = 0;
//定位到目标字符串中停止标志的位置
while (dest[i] != '\0')
{
i++;
}
//将源字符串逐次赋值到目标数组后面
while (src[j] != '\0')
{
dest[i] = src[j];
}
//赋值完成后再目标字符数组后添加停止标志,构成字符串
dest[i] = '\0';
return;
}
//比较两个字符串的大小(strcmp)
int Strcmp(char s1[],char s2[])
{
int ret;
int i = 0;
//定位到两个字符串字符不同的位置或者是某一个字符串结束的位置
while (s1[i] == s2[i] && s1[i] != '\0' && s2[i] != '\0')
{
i++;
}
//返回两个字符串定位好的位置上的ASCII码的差值,为判断大小做依据
ret = s1[i] - s2[i];
return ret;
}
二维数组作函数参数
二位数做参数时,形参为 int a[][10],int row,在本质上,二维数组是一位数组的数组,此时int[10]是该数组的数据类型,可以从int[10] a[]这种形式上理解:a为一个一维数组,只是每个数组元素有10个int类型的数据构成,为40个字节。但是C语言不支持这种语法,编译器会将这个形参理解为 int (*a)[10] ,一个数组类型的指针,所以我们在函数中算不出来整个二维数组的大小,得传入一个行数进去。
//数组参数的第一个[]中的内容也没用,第二个不能省略
//形参还得传入一个行的长度
void printfArray(int a[][10],int row)
{
int i,j;
for (i = 0;i < row;i++)
{
for (j = 0;j < 10;j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
return;
}
总结:
形参:二维数组的形式+行数
实参:数组名+行数
二维字符型数组做函数参数时,跟二维整型数组一致,也要传入行数,不要和一维字符型数组搞混。
void inputStr(char s[][50],int row)
{
int i;
for (i = 0;i < row;i++)
{
gets(s[i])
}
return;
}
//调用形式
char s[3]][50];
inputStr(s,3);
数组类型作函数参数总结
1.一维整型数组做函数参数:形参为数组形式+数组长度;实参为数组名+数组长度。
2.一维字符型数组做函数参数 :形参为数组形式;实参为数组名。
3.二维整型数组做函数参数:形参为数组形式+行数;实参为数组名+行数。
4.二维字符型数组做函数参数:形参为数组形式+行数;实参为数组名+行数。
标识符的作用域与可见性问题:
作用域:名字作用的范围。
1.局部作用域:{ }花括号范围内就叫局部作用域。
2.全局作用域:不在任何一个花括号内{ }就是全局作用域。
可见性:程序运行到某一个位置,哪些名字可以被使用(被看见)
可见性的规则:
1.先定义,后使用。
2.同一作用域不能有同名的标识符。
3.在不同作用域,同名标识符,相互之间没有影响。
4.如果是在不同的作用域,但是作用域之间存在嵌套关系,则内部作用域的同名标识符会屏蔽外部作用域的同名标识符(就近原则)。
局部变量和全局变量
空间角度看两种变量
局部变量:局部变量空间一般开在栈上;如果不初始化,局部变量中的值是随机值(垃圾值);
全局变量:全局变量空间开在全局区(静态区);如果不初始化,默认为0;
时间角度看变量(生命周期)
局部变量的生命周期:从程序运行到定义处开始存在,到程序运行到它作用范围结束时销毁。
全局变量的生命周期:从程序开始运行时存在,到整个程序运行结束时销毁。所以全局变量和静态变量不能用变量进行初始化。
存储类别的关键字:
auto:
表示它是一个自动变量(局部变量一般都是自动变量)——内存自动申请自动释放
static:
可修饰局部变量,此时局部变量会被放在全局区(静态区),此时局部变量生命周期被延长(从程序开始时存在,到程序运行结束才销毁);static修饰的局部变量只会被初始化一次,且具有继承性。static修饰的变量只能用常量初始化。static修饰全局变量,表示限定全局变量的作用域为本文件,别的文件不能通过extern来声明使用,可用来保护私有数据,防止被引用。
register:
寄存器;修饰变量表示把变量存储到寄存器中;建议性的关键字,编译器不一定采用;register修饰的变量不能作取地址操作。
extern:
(外部的)表示数据或者变量是存在外部的,不在当前文件中,多用于多文件编程;只能声明全局变量
注意
static和extern也可以用来修饰函数,extern修饰函数表示声明函数,表示函数在别处定义了;static修饰函数表示该函数只能在该文件中使用,限定作用域,别的文件不能通过extern声明函数后调用。