零碎知识点总结

这里总结一些关于语言、数据结构的一些基础知识。好记性不如烂笔头o(^▽^)o

零碎知识点总结

  • 零碎知识点总结
    • 数组和指针的区别
    • 指针数组和数组指针
    • hashmap 和 hashtable 的区别
    • 链表和数组的区别
    • 内存字节怎么对齐为什么要对齐
    • new和malloc的区别
    • 抽象类和接口的区别
    • 桥接模式和适配器模式的区别

数组和指针的区别

1、计算内存容量上的差别
当数组作为函数的形参的时候,该数组自动退化为同类型的指针

void Func(char a[100])
{
cout<< sizeof(a) << endl;   // 结果是4字节而不是100字节
}

用运算符sizeof可以计算出数组的容量(字节数);
sizeof(p)得到的是一个指针变量的字节数,相当于sizeof(char*),而不是p所指的内存容量。

char a[] = "hello world";
char *p  = a;
cout<< sizeof(a) << endl;   // 12字节
cout<< sizeof(p) << endl;   // 4字节

2、指针和数组都可以在初始化的时候赋予字符串常量
定义指针时,编译器并不为指针所指向的对象分配空间,它只是为指针本身分配4个字节的空间,除非在定义的同时赋给指针一个字符串常量进行初始化。
例如:

char *p="abcdefg"; //创建了一个字符串常量并为其分配了空间  

注意,只有对字符串常量才会如此。不能指望为浮点数之类的常量分配空间。 如:

float *pip=3.151; //错误!无法通过编译

并且初始化赋值后常量字符串的内容是不可以被修改的。数组的可以修改

char *p = “world”;     // 注意p指向常量字符串
p[0] = ‘X’;            // 编译器不能发现该**错误**

3、内容的复制和比较
  不能对数组进行字节复制和比较。对于两个数组a,b,不能用b=a进行复制,而应当使用标准库函数strcpy()。也不能使用if(b==a)进行比较,应当使用strcmp()。
  而对于指针p,如果要想将数组a中的内容复制,要先申请一块内存区域,然后使用strcpy()进行拷贝。

指针数组和数组指针

1、数组指针(也称行指针)

int (*p)[n];  //定义

()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。

2、指针数组

int *p[n];  //定义 

[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。
这里执行p+1是错误的,这样赋值也是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]…p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。

区别:

数组指针只是一个指针变量,是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。
指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。

hashmap 和 hashtable 的区别

这里有些涉及到java的知识,暂时作为学习性的放在这里,部分参考这里

HashMap和HashTable都实现了Map接口,但决定用哪一个之前先要弄清楚它们之间的分别。主要的区别有:线程安全性,同步(synchronization),以及速度

1、HashMap几乎可以等价于HashTable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而HashTable则不行)。
2、HashMap是非synchronized,而HashTable是synchronized,这意味着HashTable是线程安全的,多个线程可以共享一个HashTable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。
3、另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而HashTable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。(这一段涉及到java)

由于HashTable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过HashTable。
HashMap不能保证随着时间的推移Map中的元素次序是不变的。

1) sychronized意味着在一次仅有一个线程能够更改HashTable。就是说任何线程要更新HashTable时要首先获得同步锁,其它线程要等到同步锁被释放之后才能再次获得同步锁更新HashTable。
2) Fail-safe和iterator迭代器相关。如果某个集合对象创建了Iterator或者ListIterator,然后其它的线程试图“结构上”更改集合对象,将会抛出ConcurrentModificationException异常。但其它线程可以通过set()方法更改集合对象是允许的,因为这并没有从“结构上”更改集合。但是假如已经从结构上进行了更改,再调用set()方法,将会抛出IllegalArgumentException异常。
3) 结构上的更改指的是删除或者插入一个元素,这样会影响到map的结构。

总结:

hashmap hashtable
线程不安全 线程安全
允许有NULL的key和value 不允许有NULL的key和value
效率更高 效率相对低
不是synchronized的 是synchronized的
有containsvalue和containsKey方法 有contains方法
HashMap是Java1.2引进的Map interface的一个实现 Hashtable 继承于Dictionary 类
HashMap是Hashtable的轻量级实现 Hashtable 比HashMap 要旧

链表和数组的区别

1、数组静态分配内存,链表动态分配内存;
2、数组在内存中连续,链表不连续;
3、数组元素在栈区,系统自动申请空间,链表元素在堆区,每个元素必须手动申请,如malloc;
4、数组利用下标定位,时间复杂度为O(1),链表定位元素时间复杂度O(n);
5、数组插入或删除元素的时间复杂度O(n),每次都要移动已有元素,链表的时间复杂度O(1)。

内存字节怎么对齐,为什么要对齐

  内存对齐的话会加快访问速度,及提高内存管理效率。对齐的话用一个时钟周期就可以读出来,否则需要两个。32位系统一次去4个byte(4*8位),是按照一定的顺序的,例如,读取0、1、2、3的话一次就够了,如果是1、2、3、4的话就要读两次,先读1、2、3。
  对齐方式:数据成员对齐,结构体成员对齐,结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的整数倍.不足的要补齐。编译器默认是#pragma pack(8),所以测试我们的规则会正常;注意gcc默认是#pragma pack(4)。

new和malloc的区别

1,malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
2,对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
3,C程序只能用malloc/free管理动态内存
使用free之前要判断,使其free的指针是!NULL的,使用delete则无须判断。free()释放的是指针指向的内存!注意!释放的是内存,不是指针!释放内存后把指针指向NULL,防止指针在后面不小心又被解引用了。
4,free掉的内存是该指针指向的一段内存空间,里面应该是空的。
delete掉的内存是里面确实存有数据或者对象的。
5,new 返回指定类型的指针,并且可以自动计算所需要大小。
malloc 则必须要由我们计算字节数,并且在返回后强行转换为实际类型的指针。

抽象类和接口的区别

1、抽象类是类(Class),接口是集合(Set),两者从本质上不是一种东西。
2、抽象类是不能实例化的类,但是其中的方法可以包含具体实现代码。
3、接口是一组方法声明的集合,其中应仅包含方法的声明,不能有任何实现代码。
4、抽象类是本体的抽象,接口是行为的抽象
5、抽象类表示“是一个(IS-A)”关系的抽象,它抽象了类的本体,其使用动机是在不允许实例化的限制下复用代码。
6、接口表示“能(CAN-DO)”关系的抽象,它抽象了类的行为,其使用动机是松散对象间的耦合以及实现程序多态性。
7、“我是一个人”和“我能呼吸”分别表达了“我”和“人”以及“我”和“呼吸”的关系,前者表示“是一个”的关系,而后者表示“能”的关系。

应用场合:
优先定义接口,如果有多个接口实现公用的部分,则使用抽象类,然后集成它。

桥接模式和适配器模式的区别

共同点:桥接和适配器都是让两个东西配合工作
不同点:出发点不同。
适配器:改变已有的两个接口,让他们相容。
桥接模式:分离抽象化和实现,使两者的接口可以不同,目的是分离。

所以说,如果你拿到两个已有模块,想让他们同时工作,那么你使用的适配器。
如果你还什么都没有,但是想分开实现,那么桥接是一个选择。

桥接是先有桥,才有两端的东西。桥接是在桥好了之后,两边的东西还可以变化。
适配是先有两边的东西,才有适配器

你可能感兴趣的:(【Data,Structure】,【C/C++】,C语言的艺术)