CS107 Computer Organization & Systems 笔记

  • 第一节 字节-类型-内存

    • 一个bit可以储存一个0或1 一个字节是8 bit
    • 而char类型占据一个字节,所以能表示256个字符。而short类型占两个字节。
    • 赋值其实是按位拷贝,因此用short类型变量来赋值char类型时,只会保留short较低位的字节,高位的8bit会被舍弃。同理,用int类型(4个字节)给short变量赋值时,也只会将较低的16个bit保留,拷贝给short变量
    • 但如果将一个值为2^15的int变量赋值给short,这时原本代表数量的bit变成了代表符号的bit……会有未知后果
    • short s = -1 这里s+1就变成了全0,因此s所占的16个bit应该全是1(补码),这时如果将s赋给一个int类型的变量i呢?如果还是简单的按位拷贝然后将前面16个bit赋0, 符号位就被破坏了,因此要把符号位拉伸——前面16个bit也全赋1
    • float浮点数的表示方法:32个bit,第一个是符号位s,中间八位是unsigned int(其表示的数记为exp,显然exp介于0-255之间),后23位是小数位(记为.xxxx)。那么这个float数所代表的值就是(-1)s**1.xxxx**2(exp-127)。
      • 因此,如果int i = 5然后 float f = i ,这时5会被表示为1.25*2^2,也就是说exp为2+127,.xxxx为0.25
    • 可以这么操作:float f =((float**)&i) 这样系统会把i所占的32个字节看成用上述方法表示的float类型数,打印f会发现f是一个极小的数!(exp为0, 所以f是1. xxx2^-127)*
    • 如果, float f = 7.0;short s = ((short)&f); s会是什么呢? &f指向f所占32bit的首位,经过类型强制转换,&f所指向的内存的长度变为16bit,然后再将这16个bit按位拷贝给s!
  • 第二节 操作内存

    • 如何操纵数组中任意的内存单元 (例如对于一个int类型的数组,我们通常只能一次同时修改四个字节,但如果想单独修改其中某一个字节): 用强制类型转换,将指向数组的指针类型转换为占用内存更小的数据类型. 比如int arr[10]; ((char*) arr) +n就是指向第n个字节的指针!
    • strdup() 是string duplicate 的缩写. 这个方法能够动态地分配足够的空间来存储字符串. 然后返回字符串第一个字符的地址.
    • strcpy()第二个参数是字符串,第一个参数是要把字符串写入的地址,使用strcpy()时,会默认把第一个参数当作是任意长度字符序列空间基地址. strcpy函数会一个一个的把字符写入,包括最后的\0.
  • 第三节 用纯C(无模板)来实现泛型编程:

    • 写一个可以交换任意类型的两个变量的swap函数

      void swap(void* vp1, void* vp2,int size){
             
      	// 不能 void temp = *vp1; 
        //因为不能声明void类型变量,而且void* 也无法解引用,因为机器并不知道要提取多少个字节
      	char buffer[size];//大多数编译器不支持这个操作(数组大小为参数),可以换成动态申请内存
      	memcpy(buffer, vp1, size);
      	memcpy(vp1, vp2, size);
      	memcpy(vp2, buffer, size)
      }
      
      • 这里的memcpy()是一个比strcpy()更通用的方法, 不要求拷贝的是字符, 不关心\0,因此必须显示地指明 要从内存位置上拷贝多少个字节.
    • search函数的泛型 lsearch(void *key, void *base, int n, int elemSize);

  • 第四节 不用模版,实现泛型编程

    • 不借助模板,实现可以搜索任意类型的数组的函数 lsearch()
    void *lsearch(void *key,void*base,int n,int elemSize, int (*cmpFun)(void *, void *)
    // key 是要搜索的值的指针,base是搜索的数组,n是数组长度,cmpFun 函数用来比较是否相等
    {
         
    	for( int i = 0; i<n; i++){
         
    		 void *elemAddr = (char*)base + i*elemSize;
    		 if(cmpFun(key,elemAddr)==0) return elemAddr;
    	}
    	return NULL;
    }
    **cmpFun的实现应根据具体情况,例如要比较整数时:**
    int intCmp(void *elem1, void *elem2){
          //参数类型应该跟上面保持一致,用void*
    	int *ip1 = elem1;         //相当于将void*类型的参数强制转换为int*类型
    	int *ip2 = elem2;
    	return *ip1 - *ip2;
    }
    **那如果要实现在字符串数组(二维)中,搜索一个字符串呢?**
    char *notes[] = {
         "Ab", "F#", "B", "Gb", "D"};
    char *favoriteNote = "Eb"
    **这时的cmpFun就应该是**
    int StrCmp(void *vp1, void *vp2){
         
    		char *s1 = *(char**)vp1;
    		char *s2 = *(char**)vp2;   
    //还是将vp1vp2强制转换成本来的类型——favoriteNote和notes中的元素都是char*类型,
    //vp1,vp2作为他们的指针被传进来,类型应该是指针的指针
    		return strcmp(s1,s2); //strcmp()是内置函数
    }
    
    • strcmp()函数接收两个字符串,挨个比较每个字符,一旦遇到不相同的,就返回他们ASCII的差值
    • 内置函数中有一个bsearch() 他的功能和参数与上面我们自己写的lsearch()相同,但用的是二分搜索。
    typedef struct {
         
    	int *elems;
    	int logicalLen;
    	int allocLength;
    }stack;
    void stackNew(stack *s);
    void stackDispose(stack *s);
    
    • assert()接收一个布尔类型的参数,如果参数为真,则什么都不做,如果参数为假,则终止程序执行,并报告程序终止的位置
  • 第五节 纯C(没有类)实现栈

    typedef struct {
         
    	int *elems;
    	int logLen;    //已经使用的内存
    	int allocLen;   //申请的内存
    }stack;
    void stackNew(stack *s){
            //功能类似构造函数,其实只是顶层作用域中的普通函数
    	s->logLen = 0;
    	s->allocLen = 4;
    	s->elems = malloc(4* sizeof(int));
    	assert(s->elems != NULL);   //保险起见,验证一下内存申请是否成功
    }
    void stackDispose(stack *s){
         
    	free(s->elems);
    }
    void stackPush(stack *s, int value){
          //这个函数关键在于,当申请空间已经饱和时,将空间扩展
    	if(s->logLen == s->allocLen){
         
    		//相比C++(不得不重新申请更大内存,然后将数组中的值挨个复制过来),C能够更好地操作底层内存
    		//可以调用**realloc()**函数,他可以调整之前用malloc分配的内存块大小
    		s->elems = realloc(s->elems,s->allocLen*2*sizeof(int));
    		s->allocLen *= 2;
    		assert(s->elems!=NULL);
    	}
    	s->elems[s->logLen] = value;
    	s->logLen++;
    }
    int stackPop(stack *s){
         
    	assert(s->logLen>0);
    	s->logLen--;
    	return s->elems[s->logLen];
    }
    	
    
    • 关于realloc() : 用这个函数扩展之前申请单内存时,他首先检测当前内存后面还有没有空间,如果有则直接扩展,没有就重新找一块内存,再把原来的子节复制过来,接着把原来的内存释放掉,然后返回新内存的指针。 如果迭代时用到了realloc(),为了保持代码的一致性,在第一次申请内存时,我们可以不用malloc而使用realloc,然后第一个参数传NULL
  • 第六节

    • <
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值