一维字符型数组
一维字符型数组 --- 用来存放字符串
因为处理的是字符串数据,字符串操作的 依据,主要看结束标志 '\0'
而不是 数组长度
注意:
一维字符型数组做函数参数
形参 数组形式
实参 数组名
练习:
1.用函数完成gets的功能:
void Gets(char s[])
{
从键盘获得字符串, 放到s指定的数组空间中
最后 要保证是个字符串 ('\0')
}
具体代码:
void Gets(char s[])
{
int i = 0;
while ((s[i] = getchar() )!= '\n')//当输入回车时循环停止
{
++i;
}
s[i] = '\0';
}
2.用函数完成strlen的功能:
int Strlen(char s[])
{
统计 '\0'前面字符的个数
}
具体代码:
int Strlen(char s[])
{
int i = 0;
while (s[i] != '\0')
++i;
return i;
}
3.用函数完成strcpy的功能:
void Strcpy(char dest[],char src[])
{
//将src中字符串 复制 到dest
}
具体代码:
void Strcpy(char dest[],char src[])
{
int i = 0;
while (src[i] != '\0')
{
dest[i] = src[i];
++i;
// printf("i= %d\n",i);
}
dest[i] = '\0';//字符串要在在最后加上'\0'
return;
}
4.用函数完成strcat的功能:
void Strcat(char dest[],char src[])
{
//1.定位到 dest的'\0'位置
//2.从 '\0'位置开始拷贝
//3.dest的最后 '\0'
}
void Strcat(char dest[],char src[])
{
int i = 0;
while (dest[i]!='\0')
++i;
int j = 0;
while (src[j]!='\0')
{
dest[i] = src[j];
++i;
++j;
}
dest[i] = '\0';
}
5.用函数完成strcmp的功能:
int Strcmp(char s1[],char s2[])
{
比较结果 ,最后停的位置上的两个字符的 差值
}
int Strcmp(char s1[],char s2[])
{
int i = 0;
while (s1[i]==s2[i]&&s1[i]!='\0'&&s2[i]!='\0')
{
++i;
}
return s1[i] - s2[i];
}
二维数组做函数参数
形参 --- 二维数组形式 + 行数 //本质 一维数组 + 长度
实参 --- 数组名 + 行数 //
int sum(int a[][4],int row)或int sum(int (*a)[4],int row)
调用sum = sum(a,len);
形参里面行数可以省略列数不能省
二维字符数组
函数参数:
与二维整型数组 使用方式相同
形参 --- 二维数组形式 + 行数 //本质 一维数组 + 长度
实参 --- 数组名 + 行数 //
注意:
1.不要和一维字符型数组传参搞混
一维字符型数组,主要用来存放 字符串数据
而字符串数据有结束标志('\0'),故,传参时,不需要传长度
2.二维字符型数组,用来存储多个字符串
要操作时,往往都是操作多个字符串,而多个字符串没有所谓结束的标志。
看的是数组长度(行数)
练习:
1.实现一个输入多个字符串函数 inputStr()
void inputStr(char (*s)[10],int row)
{
int i = 0;
for (i = 0; i < row; ++i)
{
gets(s[i]);
}
}
2.插入排序,二分查找
#include <stdio.h>
#include <string.h>
void printStr(char s[][10],int row)
{
int i = 0;
for (i = 0; i < row; ++i)
{
puts(s[i]);
}
}
//void inputStr(char s[][10],int row)
void inputStr(char (*s)[10],int row)
{
int i = 0;
for (i = 0; i < row; ++i)
{
gets(s[i]);
}
}
void insertChoiece(char s[][10],int row)
{
int i = 0;
int j = 0;
for (i = 1;i < row; ++i)
{
char t[10];
strcpy(t,s[i]);
j = i;
while (j > 0&&strcmp(t,s[j-1]) < 0)
{
strcpy(s[j],s[j-1]);
--j;
}
strcpy(s[j],t);
}
}
int binaryFind(char s[][10],int row, char str[])
{
int begin = 0;
int end = row - 1;
int ret = -1;
int mid = 0;
while (begin <= end)
{
mid = (begin+end)/2;
if (strcmp(s[mid],str) < 0)
{
begin = mid + 1;
}else if (strcmp(s[mid],str) > 0)
{
end = mid - 1;
}else
{
ret = mid;
break;
}
}
return ret;
}
int main(void)
{
char s[][10] = {"hello","world","china"};
int row = sizeof(s)/sizeof(s[0]);
inputStr(s,row);
insertChoiece(s,row);
printStr(s,row);
char str[10];
gets(str);
printf("%d\n",binaryFind(s,row,str));
return 0;
}
总结:
1.一维整型数组 做函数参数
形参 --- 数组形式 + 数组长度
实参 --- 数组名 + 数组长度
2.一维字符型数组 做函数参数
形参 --- 数组形式
实参 --- 数组名
原型: 一维字符型数组 主要用来存储字符串数据
3.二维整型数组 做函数参数
形参 --- 数组形式 + 行数 //本质 就是一维数组的长度
实参 --- 数组名 + 行数
4.二维字符型数组 做函数参数
形参 --- 数组形式 + 行数 //本质 就是一维数组的长度
实参 --- 数组名 + 行数
标识符、作用域
1.作用域和标识符
作用域:名字 作用的访问
可见性:程序运行到某一个位置 哪些名字可以被使用(被看见)
作用域:
局部作用域
{
} //花括号范围内 就叫局部作用域
在局部作用域 定义的变量 --- 局部变量
在全局作用域 定义的变量 --- 全局变量
全局作用域:不在 任何一个 { } 范围之内
标识符的可见性的规则:
1.先定义,后使用
2.同一作用域中,不能有同名标识符
3.在不同的作用域,同名标识符,相互之间没有影响
4.如果是不同的作用域,但是作用域之间存在嵌套关系,
则,内层的作用域的同名标识符,会屏蔽外层的作用域的同名标识符。
(就近原则)
2.C语言的程序5个区
栈
堆 [数据区]
字符串常量区
全局区(静态区)
--------------------------------------
代码区 [代码区]
3.全局变量和局部变量
局部变量
特点:
局部变量 空间 一般都开栈上
如果不初始化,局部变量中的值是随机值(垃圾值)
全局变量
特点:
全局变量 空间 全局区
如果不初始化,默认初始化为0
3.生命周期
时间角度:生命周期
int a; //什么a的空间被开辟,什么时候a的空间被销毁
局部变量的生命周期
从程序运行到定义处开始存在,到程序运行到 它作用范围结束 时 销毁
全局变量(静态变量)的生命周期
从程序开始运行时就存在了,直到整个程序运行结束时,销毁
注意:全局变量和静态变量,不能用"变量"进行初始
全局变量:在函数外部声明的变量,整个程序都可以访问;声明时会被默认初始化,可以在任何函数中使用;生命周期长,整个程序执行期间都存在;全局变量存储在全局数据区(data)中,不能要变量初始化。
局部变量:在函数内部或代码块内部声明的变量,只能在所属的函数或代码块中访问;声明时没有默认初始化,需要手动赋值才能使用;生命周期短,只在所属的函数或代码块的执行期间存在;局部变量存储在栈区(stack)。
存储类别的关键字
[存储类别] 类型 变量名;
1. auto
auto://表示它是一个自动变量 (局部变量) --- 自动申请 自动释放
auto是C语言默认的存储类说明符,所以即使不显式使用auto,局部变量也会被认为是自动变量。
2.static
//static 修饰局部变量 此时 会被放在 全局区(静态区)
// 此时 局部变量的生命周期被延长
// 注意:
// 1.static 修饰局部变量 --只会被初始化一次
// 2.static 修饰的变量 -- 具有继承性
// 3.static 修饰的变量 -- 只能用常量初始化 (不能用变量初始化)
static
变量
局部变量
表示将局部变量存放到静态区。
延长声明周期。
存在静态区的变量
a.不能用变量初始化
b.只会被初始化一次
c.反复使用该变量时,值具有继承性。
全局变量
限定作用域为本文件,别的文件不能通过extern来声明使用
函数
限定作用域为本文件,别的文件不能通过extern来声明使用
3.register
register // 寄存器
// 表示,把变量 存储 寄存器中
关键字用于建议编译器将某个变量存储在CPU的寄存器中、寄存器变量可以比存储在内存中的变量更快地被访问,因为寄存器是CPU内部的高速存储器,不需要重复将数据从内存拿到CPU中。无地址:由于寄存器变量可能不在内存中,因此不能对它们使用取地址操作符&。局部性:register关键字通常用于局部变量,尤其是那些在循环中频繁使用的变量。注意声明为寄存器变量,但是决定权在于编译器,编译器可能会忽略这一建议,当成自动变量。
4.extern
extern //外部的 ---表示你的变量 是存在外部的 //多文件编程
//不在当前文件中
//只能 声明 全局变量
//static 修饰全局变量
//表示限定全局变量的作用域位本文件,别的文件不能通过extern来声明使用
//用途: 保护私有数据
// 防止被引用
修饰函数 //声明函数 在别处的定义的
static 修饰函数作用和修饰全局变量作用相同
限定作用域为本文件,别的文件不能通过extern来声明使用
表示变量或函数在其他地方定义,可能是在另一个源文件中、编译时要将包含变量或函数的源文件一起编译。extern通常用作声明,告诉编译器变量或函数的类型和名称,但不分配内存。通过extern,可以在多个文件中访问同一个全局变量或函数,但static修饰的变量或函数不能被外部文件访问。