原码:将最高位作为符号位(0代表正,1代表负),其余各位代表数值本身的绝对值。
反码:一个数如果值为正,那么反码和原码相同。如果值为负,那么符号位为1不变,其它各位与原码相反。
补码:正数的原码、反码、补码都相同。负数,最高位符号位为1不变,其余各位取反,最后+1。计算机存放数据都是按照补码的形式放,然后进行计算的。
1.数组
定义:内存连续,并且是用一种数据类型的变量
类型 数组名[];
在内存当中是连续的空间地址
数组初始化:类型 数组名[N]={0};表示N个元素都初始化为0。
二维数组定义:int array[3][4];
二维数组初始化:int array[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
字符串数组定义:char array[100];
对C语言字符串就是最后一个元素以'\0'结尾的数组。
字符串初数组始化:char array[]="hello";
scanf函数不安全提醒:主要是scanf函数没有解决缓冲区溢出的问题和不能成功获取完整的含空格的字符串,我们可以添加一个宏定义#define _CRT_SECURE_NO_WARNINGS或#pragma warning(disable:4996)
我们也可以用gets函数来获取一个含空格的字符串。
我们也可以用fgets函数来获取一个含空格的字符串并解决缓冲区溢出的问题,用法fgets(字符串数组名,sizeof(字符串数组名),stdin);stdin表示标准输入。fgets函数最后会自动补上'\n'
puts函数:打印字符串,与printf不同,puts函数会在最后自动添加一个‘\n‘。
fputs函数用法:fputs(字符串数组名,stdout);与puts函数区别是它不会在最后加上\n
strlen函数求字符串长度。不会将最后的\0也计算在内。
strcat(a,b);把b追加到a的后面。a必须要有足够的空间。
当a的缓冲区空间较小,b很大的时候,strcat也面临安全问题,所以要用strncat函数,用法:strncat(a,b,sizeof(a)-strlen(a)-1);这样就不会有溢出了。
memset(a,0,sizeof(a));将a内存初始化为0;
strcmp(a,"str");表示如果两个参数所指的字符串内容相同,函数返回0。
strncmp(a,"exit",4);4表示只比较前4位。
strcpy(b,a);表示将a拷贝到b。
strncpy:有限拷贝。
sprintf(a,"ni shi shui%d",3)表示将ni shi shui3输入到字符串数组a中。
strchr(a,'c'):表示在字符数组a查找字符'c',返回一个指针且指向字符‘c’的位置
strstr(a,"345"):表示在字符数组a查找字符串“345”。返回一个指针且指向字符串“345”的首地址。
strtok(a,"¥"):表示以¥为结束符,返回指向前面的字符串或字符的首地址或地址的指针。
atoi(a)函数表示将字符串a转化为整数。atof、atol都是一样的。
3.函数
在定义函数时,函数名后面括弧中的变量名称为形式参数,简称形参。在调用函数时,函数后面括号中的变量或表达式称为实际参数,简称实参。
形参在未出现函数调用时,它们并不占用内存单元,只有发生函数调用的时候形参才被分配内存,函数调用完成后,形参所占的内存被释放。
实参可以是变量、常量、表达式。
在定义函数时,一定要指定形参和实参的数据类型。
形参和实参的数据类型一定要可兼容。
在C语言中,实参和形参的数据传递是单向值传递,只由实参传递给形参,而不能由形参传递给实参。
return语句后面的语句不会被执行。
exit(0)函数表示退出程序。
头文件的使用:函数原型放在头文件里,就不用在使用函数的时候去声明该函数了,直接将放置函数原型的头文件预编译即可。使用头文件需要#include,定义头文件需要#ifndef与#endif。
函数的封装:如果放在.c文件就是代码级的封装,如果放在.dll就是二进制的封装。
动态库.dll的特点:程序运行会自动加载dll文件,且dll文件可以被多个程序调用。
静态库的特点:程序直接编译静态库,编译完成后就不需要静态库的文件了,因为已经包含在程序内部了,这样一来程序所占的内存会变大,且如果静态库的功能发生变化,就需要重新编译程序了。
linux下的动态库so文件封装示例:
新建一个a.c文件:
输入gcc -c a.c -fPIC -o a.o表示编译a.c文件,与位置无关,输出a.o文件
输入gcc -shared -o liba.so a.o表示编译一个有关a.o二进制文件的共享库
-fPIC的意思是生成一个与位置无关的代码。主要是因为每个程序都有一个入口地址(系统根据实际情况动态分配的),程序内部调用的函数距离该入口地址有一段距离叫做偏移地址,但是动态库编译的时候不知道偏移地址是多少,主要取决与哪个程序调用它,所以要指定-fPIC生成一个与位置无关的代码。
gcc链接的时候要加-shared选项,意思是生成一个so共享库。
对于linux或Unix,一个so文件,文件扩展名必须是so,文件名的前三个字母必须是lib。
要用到这个动态库文件so,需要新建一个头文件来声明动态库文件so里面的函数。输入vi a.h
#ifndef __AH表示如果没有定义一个__AH,就定义一个__AH,#define __AH表示定义一个__AH。
输入vi main.c表示编写一个可执行文件,来调用库文件.so。
输入gcc -c main.c -o main.o表示只编译不链接,指定输出文件名称为main.o
输入gcc -o main.out main.o -L. -la表示链接main.o文件,指定输出main.out可执行文件,并且在当前目录下寻找-la文件(代表liba,so文件)。
linux不再当前目录下寻找可执行程序,同时也不在当前目录下找so库文件,解决办法——修改用户配置文件:第一:cd(返回主目录);第二vi .bash_profile;第三:添加export LD_LIBRARY_PATH=$LD_LINRARY_PATH:.;第四:wq;第五:生效. .bash_profile
然后因为linux不再当前目录下寻找可执行文件,所以我们要进入main.out,如,我在1文件中存放main.out可执行文件,所以我要进入cd 1,然后输入./main.out表示在当前目录下执行main.out文件
VS2013下的代码封装
打开VS2013,新建项目,选择Win32应用程序导向
下一步
选择dll,点完成。
添加新建项.cpp文件,在里面写代码,实现判断两个数的大小的功能,编写完编译一下
寻找自己存储VS项目文件处,找到编译好的mydll.dll文件,该文件就是我们封装好的,供其它程序加载调用的动态库文件
那么dll文件怎么用呢?我们知道封装的代码功能是判断两个数的大小,这时候,我们就要新建一个项目,并且添加新建项,编写代码,一个程序的入口main。编译一下。
并将封装好的.dll文件复制到我们新建项目usedll中和可执行文件一起,并将.lib库文件放到usedll项目文件中和.c文件一起
这时候,需要一个头文件,来声明我们封装的函数和我们所需要用到的库文件,代码:#pragma comment(lib,"mydll.lib")。
成功实现封装代码的功能
dll文件封装起来,主要是给第三方使用的,这样别人就不会看到里面的代码,而且dll可以被多个程序调用,可以被其它高级语言调用。
注意C++写的函数,C语言是不能调用的,但是C++是可以调用的C语言写的函数,