C语言学习笔记(三)
* 变量
* 能使用某个变量的所有语句叫做变量的作用域
* 全局变量和局部变量重名时,语句优先调用局部变量
*
* 程序中优先使用局部变量,再考虑使用全局变量
*
* 存储区是不受作用域限制的(可以跨函数使用存储区)
* 存储区的使用受到生命周期的限制
*
* 全局变量的生命周期是整个程序执行的时间范围
*
* 局部变量的生命周期是函数某一次执行的时间范围
*
* 声明变量是可以使用static关键字,转换成静态变量
* 所有静态变量的生命周期都整个程序
*
* 没有初始化的静态变量都会是初始化为零
*
* 静态变量的初始化只在程序开始执行一次
*
* 调用函数不可以使用被调用普通局部变量的存储区,但是可以使用被调用函数的静态局部变量的存储区
指针
指针变量就是用来找到另外一个普通的变量
如果指针和数组里第一个存储区捆绑,就可以通过这个指针找到数组里的每个存储区
这个时候可以认为指针间接捆绑了数组里的每个存储区
地址数据只能参与如下三种计算过程
地址+整数
地址-整数
地址-地址
地址数据加减整数n实际上加减的是 n*sizeof(捆绑类型);
地址-地址结果代表两个地址之间包含的捆绑存储区的个数
数组中第一个存储区的地址加下标,可以得到下标代表存储区的地址
计算机对下标的处理就是用前面的地址加下标得到一个新地址,而后找到这个地址对应的存储区
所有跨函数使用存储区都是通过指针实现的
* 不要试图返回一个函数内的局部变量地址,当该函数结束时,局部变量存储区将会被释放
* 跨函数使用存储区时都需要使用指针
const
声明指针变量的时候可以使用const关键字
如果把const关键字写在类型名称前表示不可以通过这个指针对它捆绑的存储区做赋值
指针类型形式参数尽量采用上述方式增加const关键字
如果声明指针变量时在变量名称前是用const关键字就表示指针本身不可以被赋值,但
是可以通过指针对它所捆绑的存储区做赋值
void 类型名称指针 void * 称无类型指针
这种指针可以和任意类型的存储区捆绑,无法通过这种指针了解捆绑存储区的类型
这种指针前面不能直接加*取值,也不能进行数学计算,
这种指针必须首先强制类型转换成有类型指针而后才能使用*(int *) p;
无类型指针,通常做为函数的形式参数使用。
字符串
c语言中,要求所有的文字信息必须记录在一组连续的字符类型存储区里
所有文字信息必须以'\0'字符作为结尾,这个字符的ASCII码就是数字0
符合以上两个特征的内容叫字符串,他们可以在程序中表示文字信息
字符串里'\0'字符前面的内容是有效文字信息,自动忽略后面的信息
所有字符串都可以采用字符指针表示
字符串字面值
字符串字面值是一种字符串,用双引号中间包含的一组字符
编译器在编译的时候会在动在字符串字面值末尾追加一个'\0'字符
编译器会把字符串字面值替换成第一个字符所在存储区的地址
* 字符串字面值的内容在程序运行过程中是不可以改变的
* 如果程序中有多个内容一样的字符串字面值,则内存里只会记录一份
* 多个并列的字符串字面值会被合并成一个字符串字面值
字符数组
* 只有包含'\0'字符的字符数组才可以当作字符串使用
* chararr[]="abcd"; //把字面值的内容赋值给了arr[]数组,不是地址
* sizeof(arr)值为7 包括 "abcd\0";
* 字符数组里的字符串内容是可以修改的里面的内容为 "abcd\0"
#include<string.h>
操作符不可以用来操作字符串
strlen(); 统计有效字符个数
strcat(字符数组, 字符串2); 字符串2追加到字符数组后面,字符数组必须是一个数组
+当最加超出字符数组的内存超出范围,导致程序崩溃
strncat(字符数组, 字符串2, size); 类似上面,size限定字符数组后面追加多少个字符
strcat(),strncat(),返回值就是字符串1;
strcmp(字符串1,字符串2); 比较两字符串的大小,比较字符串ASCII码大小
返回1,字符串1大
返回-1,后一个字符串大
返回0,一样大
strncmp(字符数组,字符串,size); 类似上面比较前n个字符
strcpy(字符数组,字符串); 把字符串复制到字符数组内,字符串的'\0'这会被复制到
字符数组内容,因此只显示字符串的内容,返回值就是字符数组
strncpy(字符数组,字符串,size); 不保证把'\0'字符复制给字符数组,所以字符数组
原本的内容可能存留显示
memset(字符数组,'字符', size); 把字符数组里连续多个存储区内容设置成同一个字符
把字符数组前size个存储区内容换成'字符'
strstr(字符串1,字符串2); 在一个大字符串里查找小字符串的位置
返回是字符串1相同位置后面的字符
如找不到返回的是NULL;
可以实现字符串输入输出操作,这两个函数不需要包含任何头文件<无头文件>
sprintf(str,"%d%c%g", 45, 'x',5.4f);把程序中的数字按照格式放到字符数组里形成字符串
sscanf(str,"%d%c%g", i_num, c_ch,f_fun);按照格式从字符串里获得数字并记录到存储区里
可以把字符串的数字转换成数字类型 #include<stdlib.h>
atoi(字符串) 可以把字符串里不带小数点的数字转换成整数类型,返回值返回的是一个整数
atof(字符串) 可以把字符串里带小数点的数字转换成双精度浮点类型
获取字符串%s
scanf("%s",s_arr);,都取字符会产生严重错误
* fgets函数也可以从键盘得到字符串并记录到字符数组里,避免了scanf()出现的严重错误
* fgets(s_arr,size, stdin); //从stdin输入缓冲区内得到size-1个字符给s_arr,还一个是'\0'
* 如果输入内容不能充满数组就会把用户最后敲击的回车键‘\n’放在数组的最后,如果输入过多
* 就把后面的内容留到输入缓冲区内等待下次读取
*
if(strlen(s_arr)== size-1 && s_arr[size-2] != '\n')
{
scanf("%*[^\n]");
scanf("%*c");
}
char* s_arr[];
指针数组里每个存储区都是一个指针类型的存储区
字符指针数组里每个存储区是一个字符指针,每个字符指针可以用来代表一个字符串
字符指针数组可以用来表示多个相关字符串
int main(int argc, char* argv[])
{
}
宏定义
* #define PI 3.14
*
* 宏可以在编译命令里使用 —D 选项制定义宏所代表的数字
* eg: $ gcc -DPI=3.14 filename.c 在filename.c文件名编译时定义宏PI为3.14
*
* 如果程序中有些数字只能在编译的时候确定就必须用宏代表他们
*
* #define CIRCLE(r) 2*PI*r
*
* 宏的参数不一定代表数字,所以宏参数没有类型
* 如果宏有多个参数就需要用逗号把他们分开
*
** 宏不可以使用自己的存储区和函数进行数据传递,所以宏没有形式参数也没有返回值的
** 能当做数字使用的宏必须编写成表达式(因为宏没有存储区放返回值的)
** 宏的参数直接代表函数的存储区
* 不要把自增,自减的结果作为宏的参数使用
*
所有写成表达式的宏都必须写在一对小括号里面,这也可以保证优先计算宏里面的操作符
宏的所有能当做数字使用的参数也应该包含在小括号中间
宏没有返回值
宏没有形式参数
#是一个宏操作符,它可以把一个宏的参数转换成字符串字面值
#define STR(n) #n
STR(2+ 3); ---> 替换后 "2 + 3"
##它可以把一个代表示符的宏参数和其它内容连接形成一个新的标识符
#defineLOCAL(n) l_##n
intnum = 0;
intLOCAL(num) = 0; ---> 替换后 l_num
条件编译
#ifdef //表示它后面的宏名称被定义过就编译前一组语言句,否这编译后一组语句
/ #ifndef //------------------没被定义过..............................
……
#else
……
#endif
#if defined(MAX) //如果MAX定义了返回真
……
#elif(可以多次) // !defined(MAX) && defined()
……
#else
……
#endif //以上结构也可以实现条件编译,它可以根据任意逻辑表达式的结果从几组语句中选择一组编译
多文件编译
头文件内只要不分配内存的内容都可以写在头文件里。
#ifndef__FILE_H__
#define__7FILE_H__
……
#endif//__FILE_H__
使用extern声明变量的语句通常放在头文件里
静态全局变量不可以被其它文件里的语句使用
< 续:C语言学习笔记(四)>