07_02
07_03
// myatoi实现: elementtype myatoi(const char* str);
// 转译str所指的字节字符串中的整数值, 转化成一个合适的整数输出。
//例子: hao123:123 -hao123:123 hao-123:-123 hao123de-45:12345 +123haode: 123 haode-45ni321:-45321
#define MAXSIZE 100
typedef long long elementtype;
elementtype strtonum(int numbers[], int size)
{
elementtype ret = 0;
elementtype weight = 1;
for (int i = size - 1; i >= 0; i--)
{
ret += numbers[i] * weight;
weight *= 10;
}
return ret;
}
elementtype myatoi(const char* str)
{
elementtype ret = 0;
int isfirstnumber = 1;
int flag = 1;
int numbers[MAXSIZE];
int size = 0;
while (*str != '\0')
{
if (*str >= '0' && *str <= '9')
{
if (isfirstnumber)
{
if (*(str - 1) == '-')
{
flag = -1;
}
isfirstnumber = 0;
}
numbers[size++] = *str - '0';
}
++str;
}
ret = strtonum(numbers, size);
return flag * ret;
}
int main()
{
char str[MAXSIZE];
elementtype numinstr;
scanf_s("%s",str,MAXSIZE);
numinstr = myatoi(str);
printf("%lld\n", numinstr);
return 0;
}
C语言基础
静态类型:编译的时候就知道每一个变量的类型,因为类型错误而不能做的事情是语法错误(能做到运行前错误检查,故语言本身就能提供类型报错、代码提示、自动补全等功能,IDE也能提供各类服务,比如智能的rename、快捷进入相应类内部阅读代码等)。
动态类型:编译的时候不知道每一个变量的类型,运行时进行类型检查和绑定,因为类型错误而不能做的事情是运行时错误
所以C语言是静态类型语言
强类型:不容忍隐式类型转换(类型转换是指将数据由一种类型变换为另一种类型。在编译器自动赋值时,会发生隐式转换,但在代码中,也可以用一些写法强制要求进行显式转换。例如:在表达式 5 + 2.0 中,整数 5 被隐式转换为浮点数
弱类型:容忍隐式类型转换
所以C语言是弱类型语言
各种类型语言列举:
弱类型、静态类型 : C/C++
弱类型、动态类型: JS/VB/Perl/PHP
强类型、静态类型 :Java/C#
强类型、动态类型 :Python, Scheme
静态显式类型 :Java/C
静态隐式类型 :Ocaml, Haskell
数据类型及大小
决定了一个变量在内存空间中所占空间的大小
- char字符型1 byte
- short短整型2 byte
- int整型4 byte
- long 长整型4 byte
- long long更长的整型8 byte
- float 单精度浮点型4 byte
- double 双精度浮点型8 byte
关于变量的作用域和生存期
常量
字符常量本质是一个整数(ASCLL),可以进行隐式的转换
字符串赋初值和字符串长度的问题
转义字符的重要用法
C语言进阶
1、下面的代码该如何理解?
a+++++b;
理解:(a++)+(++b);
原因:c语言词法分析时有一个重要的规则叫贪心算法
((a++)++)+b ?? // error:因为(a++)不可以作为左值
2、对比下面的程序(说说你的看法)
if (x > big) big = x;
if
(
x
>
big
)
big
=
x ;
都是正确的
3、下面的程序是什么意思?有什么问题吗?
观点1:错误
struct{};后面应该加 “;”
观点2:正确
main函数的返回值是一个struct logtime类型
4、下面的代码能编译通过吗?
编译可以通过吗? // 可以
表达有问题吗? // 有问题,因为无论如何if的判断语句永真
语义分析:程序员的意思是n在【1,10】之间就执行代码,但是编译器编译时n>=1为真(1),10>=1也为真(1);n>=1为假(0),10>=0也为真(1)。所以永真
5、下面代码输出结果是什么?为什么?
输出未空:
原因:else只和它上面最近的未匹配的if配对,
int main()
{
int a = 7, b = 6;
if (a == 6)
{
if (b == 7)
{
printf("A");
}
else
{
printf("B");
}
}
return 0;
}
6、下面的代码有错误吗?
i<=N;越界访问,正确是i<N;越界访问编译时是可以正常编译的
C语言杂项
1.数组的赋值
int arr[10]={1,2}的意义为将数组arr前2个元素初始化为1,2后面的元素初始化为0。
2.下面程序会输出什么?
#include<stdio.h>
int main()
{
printf("%d\n",5/2);
printf("%f\n",5/2);
printf("%d\n",5%2);
printf("%f\n",5/2.0);
printf("%d\n",5/2.0);
return 0;
}
原因在于printf函数printf函数不会进行任何类型转换,它只是从内存中读出你所提供的元素的值,5/2的算术表达式的到的是一个整型常量2,它被以整型存储在内存中。
在编译环境下,float和int均为四字节,而浮点常量则是以8字节的double进行存储,而printf输出时,float是当double处理的,同样是使用8字节,当一个四字节数据用八字节浮点数的形式读出的时候,也就是会读之前的很多位0,最后按照(有效数字)×(基数2)pow(指数)的方式来取数,自然结果是0.000000
3.typedef
4.static
代码1会输出十个1。而代码2则会输出0~9
变量:
1.局部变量
普通局部变量是再熟悉不过的变量了,在任何一个函数内部定义的变量。编译器一般不对普通局部变量进行初始化,也就是说它的值在初始时是不确定的,除非对其显式赋值。普通局部变量存储于进程栈空间,使用完毕会立即释放。
静态局部变量使用static修饰符定义,即使在声明时未赋初值,编译器也会把它初始化为0。且静态局部变量存储于进程的全局数据区,即使函数返回,它的值也会保持不变。其作用域为局部作用域,当定义它的函数结束时,其作用域随之结束。
可见,静态局部变量的效果跟全局变量有一拼,但是位于函数体内部,就极有利于程序的模块化了。
2.全局变量
全局变量定义在函数体外部,在全局数据区分配存储空间,且编译器会自动对其初始化。
普通全局变量对整个工程可见,其他文件可以使用extern外部声明后直接使用。也就是说其他文件不能再定义一个与其相同名字的变量了(否则编译器会认为它们是同一个变量)。
静态全局变量仅对当前文件可见,其他文件不可访问,其他文件可以定义与其同名的变量,两者互不影响。
在定义不需要与其他文件共享的全局变量时,加上static关键字能够有效地降低程序模块之间的耦合,避免不同文件同名变量的冲突,且不会误使用。
3.函数
函数的使用方式与全局变量类似,在函数的返回类型前加上static,就是静态函数。静态函数只能在声明它的文件中可见,其他文件不能引用该函数。不同的文件可以使用相同名字的静态函数,互不影响。非静态函数可以在另一个文件中直接引用,甚至不必使用extern声明。
5.结构体
07_04
分支语句(选择结构)
表达式内的关系操作符与逻辑操作符:
else
else 与相邻最近的if匹配(就近)
else会与第二个if匹配而不是第一个
正确的写代码规范十分重要,如下这样写就不会有问题:
switch
1.switch中必须为整型或者字符型表达式
2.break语句建议在每个case后加上,避免以后修改时忘记添加3. default只能出现一次
循环语句
while
while语句中的break与continue:
break:跳出当前循环
continue:跳过本次循环后面的所有语句,接着执行下一次循环
示例一:
示例二:
示例三:
do…while
for
词法分析
字符与字符串
07_05
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
//字符串的左旋问题包含两点:
//1.左旋字符串
//2.判断字符串是否是另一个字符串左旋得到的
void LeftRotateOne(char str[], int size)
{
char tmp;
int i;
if (str == NULL||size==1)
{
return;
}
tmp = str[0];
for (i = 1; i < size; i++)
{
str[i - 1] = str[i];
}
str[size - 1] = tmp;
}
void LeftRotate_N(char str[], int size, int n)
{
if (str == NULL)
{
return;
}
for (int i = 0; i < n % size; i++)
{
LeftRotateOne(str, size);
}
}
int LeftRotateCmp(char str1[], char str2[])
{
int len1 = strlen(str1);
int len2 = strlen(str2);
if (len1 != len2)
{
return 0;
}
for (int i = 0; i < len1; i++)
{
if (strcmp(str1, str2) == 0)
{
return 1;
}
LeftRotateOne(str1, len1);
}
return 0;
}
int main()
{
char str[] = { "abcd" };
char str1[] = { "davb" };
char str2[] = { "dabc" };
int size = strlen(str);
int n = 21;
printf("%s\n", str);
LeftRotateOne(str, size);
printf("leftRotat %d->%s\n", 1,str);
LeftRotate_N(str, size, n);
printf("leftRotat %d->%s\n", n, str);
if (LeftRotateCmp(str, str2))
{
printf("ok\n");
}
else
{
printf("no\n");
}
return 0;
}
函数
自定义函数
函数的声明与定义不一样
函数声明就像你在main函数开头初始化变量,它的作用就是让main函数顺序执行到调用语句时知道这个你在前面说过;
如:
int max(int a, int b);
函数定义就需要具体实现这个函数的功能。
嵌套调用
链式访问
递归
程序调用自身的编程技巧称为递归( recursion)
递归的两个必要条件
1.递归出口。
⒉.递归关系。
求第n个斐波那契数先用数组法
但是在递归法过程中,如果给的n很大它会重复计算很多次,不断调用意味着更大的空间。可能造成栈溢出(stack overflow)所l以下面这个做法也许是解决这一类问题的好做法
指针
指针的大小:
1.指针是用来存放地址的,地址是用来唯一标识一块内存的。
⒉.指针的大小在32位平台是4个字节,在64位平台是8个字节。
指针类型
指针类型的作用
1.指针的类型决定了指针向前或者向后走一步有多大
可以看到:
字符指针加一只增加了一个字节;而整型指针增加了四个字节
(char)为强制类型转换因为n是整型所以n的指针应该是int
⒉指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
比如: char的指针解引用就只能访问一个字节,而int的指针的解引用就能访问四个字节。
0x11223344是16进制数,16进制数一位就是四个二进制位。所以16进制数每两位就代表一个字节。
所以地址一般用16进制位表示。
%x、%X、%#x、%#X的区别
野指针
概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)指针变量在定义时如果未初始化,其值是随机的,指针变量的值是别的变量的地址,意味着指针指向了一个地址是不确定的变量,此时去解引用就是去访问了一个不确定的地址,所以结果是不可知的。
1.野指针成因
- 1.指针初始化
- 2.小心指针越界
- 3.指针指向空间释放即使置NULL
- 4.指针使用之前检查有效性
防止指针未初始化我们可以这样做:
指针计算
07_06
机器学习
监督学习:supervised learning
对于一个样本都有一定的特征,满足一定的特征有确定的答案
非监督学习:unsupervised learning
半成品学习:semi-
强化学习 :reinforcement learning