static、extern等关键字 作用域 字符数组

一维字符型数组

一维字符型数组 --- 用来存放字符串 

因为处理的是字符串数据,字符串操作的 依据,主要看结束标志 '\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修饰的变量或函数不能被外部文件访问。

  • 18
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值