该篇开始记录中科院实习的相关知识。
该篇是之前学习C语言时的一些笔记。
C语言
过来的第一天被问了几个问题,用惯了python,突然感受到死去的记忆在攻击我。
python与C语言的区别
对于这个问题,老师强调的是C是编译型语言,而Python是解释型语言。 以下为详细解释:
编译型语言:是一种需要在程序执行之前通过编译器将源代码转换为机器码或字节码的语言。编译器会对整个源代码进行静态分析、语法检查和优化,并将其转化为可执行文件。在运行程序时,计算机直接执行这个可执行文件,而不需要再次进行翻译或解释。常见的编译型语言有C、C++、Java(部分编译过程)等。
编译型语言的主要特点包括:
- 执行效率高:由于源代码在执行之前已经被编译成机器码或字节码,因此执行速度通常较快。
- 可移植性较差:编译型语言的可执行文件通常是与特定的操作系统和硬件相关的,因此需要针对不同的平台进行重新编译。
- 开发周期相对较长:编译型语言需要在编译阶段进行额外的时间和工作量。
解释性语言:解释型语言是一种在程序执行过程中逐行解释和执行源代码的语言。解释器会逐行读取源代码,并将其翻译成计算机可以理解的形式并立即执行。常见的解释型语言有Python、JavaScript、Ruby等。
解释型语言的主要特点包括:
- 执行效率相对较低:由于解释器需要在运行时逐行解释和执行源代码,所以相对于编译型语言,执行速度通常较慢。
- 可移植性较好:解释型语言的源代码可以在不同的平台上直接运行,不需要重新编译。
- 开发周期相对较短:解释型语言通常具有更快的开发和调试周期,因为无需进行编译和链接等额外的步骤。
C语言基本知识
C语言最经典的问题就是各个数据类型的字节数,这里索性拿出我本科阶段在学习C语言时做的笔记。
数据:数据类型、变量、常量、输入、输出、运算符
基本数据类型(本质为所占内存大小决定其所属类型)
可以用sizeof()求出数据类型大小->sizeof():单位为字节
一个字节=8个bit 位
- 字符型:char 1个字节
- 无符号数:0-255
- 有符号数:-128-127(0的源码补码反码全是0000 0000 ;若补码是1000 0000 则为-128)
- 整型:int 4个字节
- unsigned int(无符号数):0-2^32-1
- 有符号数:-2^31-2^31-1 符号位:0:正数 1:负数
- 短整型:short int(short) 2个字节 (-32768
32767,FFFF7FFF) - 长整型:long int(long)8个字节
- 浮点型:float(小数点后6位)4个字节
- 双精度型:double float 8个字节
数据转换
数据类型转换时会出现高位丢失:当将一个较大的数据类型转换为较小的数据类型时,如果数据超过了目标数据类型的表示范围,就会发生高位丢失。这是因为较小的数据类型无法容纳较大数据类型所表示的所有值。
例如,当将一个32位的整数(如int)转换为16位的整数(如short)时,如果32位整数的值超过了16位整数的表示范围,高位的部分将会被丢失。
举个例子,假设有一个32位的整数值为 40000,用二进制表示为 0000 0000 0000 0000 1001 1100 1000 0000。将其转换为16位的整数时,高位的部分将会被丢失,只保留低位的部分。因此,16位的整数只能表示的范围是 -32,768 到 32,767,因此 40000 超过了这个范围,转换后的值会发生溢出,结果可能是不准确的。要避免高位丢失的问题,在进行数据类型转换时,需要确保目标数据类型可以容纳原始数据类型的范围。或者,在进行转换之前,可以进行范围检查和适当的处理,以确保数据的完整性和正确性。
所有数据在计算机存储的形式都是补码形式(正数正反补都相同)
源码:1000
反码(将除符号位的其他数取反):1110
补码(反码加1,符号位参与计算):1111
两个例子:
若输入整型数130 000000000000000000000000,1000,0010(正数的正反补都相同)
若输入整型数-130 100000000000000000000000,1000,0010
反码 0111 1101
补码 0111 1110
ASCII码(American Standard Code for Information Interchange,美国信息交换标准代码)是一种广泛使用的字符编码系统,用于将字符映射为数字值。ASCII码使用7位二进制数表示128个字符,包括英文字母、数字、标点符号和一些特殊控制字符。
以下是ASCII码中一些常见字符的对应数值:
1)大写字母A到Z:65到90
2)小写字母a到z:97到122
3)数字0到9:48到57
4)标点符号:一些常见标点符号的ASCII码包括逗号(44)、句号(46)、问号(63)等
5)控制字符:包括回车(13)、换行(10)、制表符(9)等
需要注意的是,ASCII码是基于拉丁字母的字符编码系统,不包括非拉丁字母字符、特殊符号和其他语言的字符。为了满足更多字符的需求,后来出现了扩展的字符编码系统,如Unicode。对于一个给定的字符,可以通过查找ASCII码表或使用编程语言中的内置函数来获取其对应的ASCII码值。
记住几个Ascall码
A:65 a:97 0:4
变量
int a =10实质是某块命名位a的内存的赋值(要进行变量初始化,尤其在指针里)
变量的命名不要有空格及特殊字符;
常量
define max 10(预处理时就进行替换)
const int b =10;(定义常量,由他修饰的常量不可再改变)
输出:printf
- %d:十进制数据(%+d,输出+…,%-d,输出左对齐)
- %u:无符号十进制数据
- %f:输出小数(默认6位,%2.f:输出两位 %10.2:总长为10)
- %c:输出单个字符
- %s:输出字符串以\0结束 (%7s:输出长度为7,%-7s:左对齐,%.2s:只输出两位,%2.7s听后面的)
输入:scanf
scanf(“%”,&a);
scanf(“%d %d %d”,&a,&b,&c); 若输入18,19,20输出18 0 0,因为我的scanf语句中,%d与%d中间是空格隔开,所以要严格按照他的输入方式输入。
输入不能加\n,scanf会把\n读取,当作特殊符号,只有输入下一个数据把他挤出才能跳出 。
运算符:单目、双目、三目
单目运算符:=(赋值运算符) + - * /(算术运算符)
逻辑运算符(非0都是真 ):&&(且) ||(或)^(异或 )
双目:a +=1:a =a+1 a=i++->a=i,i=i+1;a=++i,a=i+1;
三目: ?: ?前面为真赋值给:前,反之赋值给:后的数
优先级:()>算术、双目运算符>逻辑运算符>赋值运算符
!>算术运算符>关系运算符>&&和||>赋值运算符
例:
a=-1 ;b=0; c=1; d=0 ;
d=a++ && ++b || c++
a=0 b=1 c=1(||左边为真,c++就不执行了) d=1
上述只将a改为0
a=1 b=0 c=2 d=1
程序整体框架、函数、注释(//)等
整体框架
int <stdio.h>//头文件,包含一些for while等类型的函数
int main() //主函数
{ //作用域
printf("%+。。”,。);
return 0; //返回值
}
条件判断
if(0==a)//这样写不容易出错
swich(){case:}//用于多分支
//若a为字符型,case:''
循环结构
for()
while()
do while until
for(i=0;i<n;i++)
{
}//注:一些经典for的双循环、循环整除取余法
函数
函数:函数名+函数主体
有返回值int fun(int a,int b)
无返回值void fun (int a,int b)
递归算法(是for循环的一种替代)
int add(int a)
{
int sum;
if (a==1)
{
return 1;
}
else
{
sum = sum + add(a-1);
}
return sum;
}
**函数传递的是值,而不是变量本身,数值的传递对于变量本身没有影响,只能通过指针去修改 **
*a(指针)
函数(&a,&b)
int hanshu(int *a,int *b)
{
}
指针
本质
本质是变量,但是存储的数据是地址,通过这个地址能找到我们想要的数据
char int float;
int *ptr= &a;
// * ptr取值符号,取该地址下的数,他是可以修改值的
ptr:存放的是地址的参数
b=++ * ptr *ptr存放的数加一赋给b
b= * ptr++ *ptr存放的数赋给b,然后ptr所代表的地址再加上相应的数
常量指针和指针常量
const int * ptr =&a
常量指针 这个指针指向的是一个常量 a可以修改
int * const ptr =&a
指针常量 指针是一个常量,地址不可被修改
二级指针:
int a=10;
int * ptr = & a;
int ** ptr1 = & ptr;
printf("%d\n",* ( * ptr1));
ptr存放的是a的地址,ptr1放的是ptr的地址,*ptr1取的是ptr地址下存放的值即a的地址,*( * ptr1) = * ptr = 10
数组
一维数组
1)定义:是一组数据类型相同的数据 int a[常量]
2)特点:
a.数组中所有的数据都是相同的数据类型
b.int a[10];//a[0],a[1]…a[9]
注:不可在过程中定义数组大小,define N 10 ->int a[N];这样也可定义数组
c.数组中的元素的首地址都是连续的,a[0]:0x0000 a[1]:0x0004
4)赋初值的方式:
a.在定义时赋值 int a[10]={1,2,3,4,5,6,7,8,9,10}
b.循环赋值 for(…)
5)数组与指针的联系:
数组的名字是可以当成指针来使用的
int a[10];a存放的是数组首元素的地址-整个数组的首地址
a=&a[0],a+1=&a[1]
a=&a,&a+1->是整个数组的地址加1,直接越过数组到下一个数组的地址
6)辨析:
sizeof(a)计算整个数组的大小
sizeof(*a)计算a[0]的大小
sizeof(&a)计算指针的内存大小
7)数组作为函数传递时,数组名会被弱化成指针。
二维数组
a[ ][ ],前者为行,后者为列
a[2][3]:a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2]
赋值{1,2,3,4,5,6} {{1,2,3},{4,5,6}}与for循环赋值
字符数组
char str[ ]="";
printf("%s\n",str);
- \0:字符串默认以\0结尾
- 字符数组可以对单个字符数组操作:用指针。
*(str+1)='1'将第二个字母改为1;
- 常用函数:
- 库string.h
- strlen( ):计算字符串长度->只计算长度,不包括\0;
- 注意与sizeof( ):包括\0的区别,是内存大小。
- strcat( ):拼接字符串
- strcmp( ):比较两个字符串的大小 本质是逐个比较每个字符的ASCALL的大小
- strcpy( ):拷贝字符串,包括\0
辨析:
- 指针数组:本质是一个数组,数组里每一个都是指针int * a[10]: a[0] a[1] a[2]…每一个都是指针 * a[0]才是取值。它的每个指针指向的地址是连续的。每个指针的本身的地址也是连续的。
- 数组指针:int (* pa)[10] pa=&a;* pa=a
- 函数指针:void (* fun)(int )
- 指针函数:int* fun() 返回值是一个指针:这个指针不能指向局部变量
计算机内部的分配区域
变量:作用域
int main()
{
int a;
}
1)栈(计算机内存的一部分,自下而上):系统栈和函数栈 栈是会放满的 出了作用域就无效的变量:局部变量
2)堆(也是用来存放变量的,自上而下):堆的空间要比栈大得多 由用户自己申请,并且由用户自己释放(如果不释放,会造成内存泄露)。寿命是由用户决定的 。
#include <stdlib.h>
int * d=(int * )malloc(sizeof());
if (NULL==d)
{
printf(“malloc fail!\n”);
return -1;
}
free(d);
3)静态全局区:
- .bss段->未初始化的全局和静态变量
- .data->已经初始化的全局变量
- 全局变量:对所有文件可见 生命周期是当程序结束时被销毁(少用全局变量)
- 静态变量:由关键字static修饰的变量
- 特点:修饰局部变量-a.在函数结束时不会被系统回收,只在程序结束时被销毁b.只初始化一次
- 修饰全局变量:只对本文可见
4)文字常量区:字符串常量(常量的特点:不可修改)
char *str2 =”hello”;不可被修改
char str1[ ]=”hello”;
5)代码段
结构体
struct 结构体名称
{
};
结构体的内存对齐:1)方式为以最大的数据类型为单位进行字节对齐,如结构体中有int char类型按int4个字节为单位计算。
例:char a;char b;int c:8个字节
char a;int b;char c:12个字节
char c[5];char a;int b:12个字节
数组是数据结构,它还属于字符型,他可以拆开放。
注意养成大小由小到大排列
指针也属于数据类型:
char * c[5]; 8*5=40个字节
char * b; 8字节(最大)
int a; 8字节
40+8+8=56个字节
char ( * c)[5]; 他与char * b一样,声明了一个指向长度为 5 的字符数组的指针 c。
char * b;
int a;
8 * 3=24
如果是结构体嵌套,就将结构体展开,看最大的数据类型;
数值在计算机内的存储方式:大端模式、小端模式
大端模式:将数值的高位存储在低地址中
小端模式:将数值的高位存储在高地址中
共用体(联合体)
union 共用体名称
{
int a;
char b;
};
遵循原则:1)必须要能放下最大的变量
2)该内存值要是所有的数据类型的整数倍
枚举
enum DAY
{
MON,TUE,WED,THU,FRI,SAT,SUN
};
typedef 和 define
define:单纯的代码替换,不是类型替换
#define f(x) x * x;
c = f(a) / f(b);c = a * a/b * b
#define INT int *
INT a,b;//为int * a,b
typedef为全部替换
排序
排序算法(6个)
1)冒泡排序:大循环套小循环
2)快速排序:冒泡的优化
算法的时间复杂度计算
O(n)
复杂的函数声明的解析
- (void (signal(int,func))(int)); 其中signal(int,func)是函数名,其实是一个指针
- void(*a)(int) ; * * fun 指向函数这个地址的指针
2)atoi—ASCII to integer,将字符串转换成整形,从数字或正负号开始转换,一直到非数字为止
itoa—integer to ASCII–将整形转换成字符串
atof—ascii to float–字符串转换成浮点型