c语言点滴记录1106

在这里整理最近查看到的博客。一方面,整理并记录知识;另一方面,整合一下学习的基础知识,打牢基础。废话不说,开始整理:

  • 原、反、补码的思考

计算机的深入思考,为什么机器中计算都用的是补码而不是原码或是反码呢?原因有两个:补码表示的范围更广。针对于一个字节,可以表示从-128到127,(-128的补码是10000000),而原码和反码都有正负零的存在,表示的范围只能是-127到+127;补码更利于计算,并且可以简化电路设置(硬件只实现加法器就好了)。两个数相减,这要将减数转换成负数的补码,然后做位相加就好了。例如,1-128可以转化成0000 0001 +1000 0000=1000 0001,结果为-127。

  • 函数返回一个二维数组

    一个函数返回一个二维数组。首先,要向内存中申请一个相应长度的一维指针数组,数组中每个元素指向一个一维数组;然后,动态申请一个一维数组空间;最后,将一维数组的首地址值赋值给指针数组的一个元素。如果二维数组有N行,那么就要重复步骤2、3,直到将N行赋完值。在写代码之前,需要直到的是,二维数组在内存中是以一维形式存储的(可以写代码验证一下吆!)。具体代码如下:

//函数返回二维数组
char** getArray(int n/*row*/,int m/*collumn*/){
    char** arr = (char**)malloc(sizeof(char*)*n);
    char *p=(char*)malloc(sizeof(char)*n*m);//一下子分配出所有元素
    if(arr && p) {
        int i;
        for(i=0; ielse{
        free(p);
        free(arr);
        arr=NULL;       
    }
    return arr;
}

//验证二维数组在内存中存储的形式
#include 

void main(){
    int a[2][3]={1,2,3,4,5,6};
    int *p = (int*)a;
    int i;
    for(i=0; i<6;i++)printf("%d->",*p++);
    printf("\nint* visited all 2dimension array.\n");
}
  • malloc分配内存深入理解

    malloc(0)是不会产生错误的,这是这一小节的前提(如果你不服,可以上机检查一下!)。下面解释原因,malloc在分配空间的时候会额外分配一小部分空间(一般为8B),这一部分空间用来维护堆上的内存分配链表。详情点击

  • 学习使用void*

    指针一般包含两个属性,一个是标记内存分配的起始地址,另一个是告诉编译器向后寻找内存的步长。例如,int* p=malloc(sizeof(int)*n),p一方面告诉编译器分配内存的地址,另一方面告诉编译器访问的步长是4B。
    void类型的指针,一种特殊的指针,只有内存的起始地址,而不知道访问内存的步长。由于void型指针的特殊性,这类指针在使用时要时刻记住进行指针类型的转换。查看详情

  • 封装使用自己的类库

    查看详细内容

  • c语言回调函数

    回调函数的核心就是函数指针。函数指针作为另一个函数的参数,传递给这个函数后,这个函数可以使用这个指针访问其指向的函数,从而完成对该函数的调用。在这里需要明确函数指针的定义和使用。如何认识指针?把它当做一种数据类,或者更确切地说是看成一种特殊的指针。下面看一下代码。

#include 

/*funtion pointer typedef*/
typedef int (*PFUN)(int,int);

void use_fun_pointer(int n,PFUN func){

        printf("%d\n",n+func(2,3));
}

int func(int a,int b){
        return a+b;
}

void main(){
        PFUN f=&func;
        use_fun_pointer(-5,f);
}

代码输出结果为0
上面的代码可以将函数指针理解成是一种特殊的类型,更是一种指针。理解了函数指针,那么C#中的代理机制应该就好理解一些了。

  • Linux中内核中使用链表记录空间

我们在学习数据结构的时候,接触到的是如下形式来构建链表的:

struct Node{
    int data;
    struct Node *next,*pre;
};

但是,Linux内核中使用的链表实际上是这样的吆:

struct list_head  
{  
    struct list_head *prev,*next;  
};  

struct entry  
{  
    struct list_head* list;  
    type data;  
};  

注:上面的代码,正好说明了为什么malloc(0)回分配8B空间了,占空间的是entry中的list指针,而list指针结构体中含有两个指针,那么这两个指针分别占4B。
看了上面的代码,大家有没有产生一个疑问,如果我知道entry的实例,我很容易范文data属性。然而,在linux内核中我们会只知道链接各个内存块的链接(即entry中的list属性)。那么,我们怎么才能只知道list的情况下找到data呢?以前没学过呀,我怎么知道呢?下面学习一下新知识。

#define list_entry(ptr, type, member) container_of(ptr, type, member) 

#define container_of(ptr, type, member) ({ / const typeof( ((type *)0)->member ) *__mptr = (ptr); / (type *)( (char *)__mptr - offsetof(type,member) );})  

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)  

解释都不说了,因为比较复杂,也很绕。给出一个参考链接。

  • 结构体的深浅拷贝

只贴代码吧!代码来自链接!

typedef struct Teacher   
{  
    char name[20];  
    char *pname;  
    int age;  

}Teacher;  

void copyStruct2(Teacher *to,Teacher* from)  
{  
    //  *to = *from;//编译器的==操作 只会把指针变量的值copy,但不会拷贝指针变量所指的内存空间,浅拷贝  
    memcpy(to,from,sizeof(Teacher));  
    to->pname = (char *)malloc(20*sizeof(char));//深拷贝  
    strcpy(to->pname,from->pname);  

}  
  • 野指针问题

产生野指针的原因如下:
(1)指针变量未初始化
任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。
(2)指针释放后之后未置空
有时指针在free或delete后未赋值 NULL,便会使人以为是合法的。别看free和delete的名字(尤其是delete),它们只是把指针所指的内存给释放掉,但并没有把指针本身干掉。此时指针指向的就是“垃圾”内存。释放后的指针应立即将指针置为NULL,防止产生“野指针”。
(3)指针操作超越变量作用域
不要返回指向栈内存的指针或引用,因为栈内存在函数结束时会被释放。示例程序如下:

class A {
public:
  void Func(void){ cout << “Func of class A” << endl; }
};
class B {
public:
  A *p;
  void Test(void) {
    A a;
    p = &a; // 注意 a 的生命期 ,只在这个函数Test中,而不是整个class B
  }
  void Test1() {
  p->Func(); // p 是“野指针”
  }
};

函数 Test1 在执行语句 p->Func()时,p 的值还是 a 的地址,对象 a 的内容已经被清除,所以 p 就成了“野指针” 。

  • const变量不能更改吗?

    常识性知识,直接贴代码(c语言):

void getMem(const char *p)  
{  
    //p =1;//编译通过   
    //p[1] = 0;//报错 左值指定const对象 指针所指向的内存空间不能被修改  
}  
void getMem2( char const *p)  
{  
    //p =1;//编译通过   
    //p[1] = 0;//报错 左值指定const对象 指针所指向的内存空间不能被修改  
}  
void getMem3( char* const p)  
{  
    //p =1;//编译不通过 const修饰p p的值不能被修改   
    p[1] = 0;//编译通过 ,p指向的内存空间可以被修改  
}  
void getMem4(const char* const p)  
{  
    //p =1;//编译不通过 const修饰p p的值不能被修改   
    //p[1] = 0;//报错 左值指定const对象 指针所指向的内存空间不能被修改  
}  

C++的世界里,是这样的:c++中的const是真正的常量,存放在const符号表中,只有当const常量为全局在其他文件中使用使用&操作符取const的地址的时候才分破存储空间。

    const int b =20;  
    int *p = NULL;  
    p =(int*)&b;  
    *p =60;  
    printf("b:%d\n",b);//20  
    system("pause");  
    return 0;

你可能感兴趣的:(c语言)