# 斯坦福编程范式 CS107_5
# 接着上节课的例子
void *lsearch(void *key, void *base,int n,int elemSize,int (*cmpfn)(void *,void *)){ | |
for(int i=0;i<n;i++){ | |
void *elemAddr = (char*)base + i * elemSize; | |
if(cmpfn(key,elemAddr) == 0) //cmpfn 函数就是比较传入的地址中的内容是否一样 | |
return elemAddr; | |
} | |
return NULL; | |
} |
下面是一个使用上述函数的例子
int array[]={4,2,3,7,11,6}; | |
int size = 6; | |
int number = 7; | |
int *found = lsearch(&number,array,6,sizeof(int),IntCmp); //IntCmp 是用来比较的函数,之后再进行实现 | |
int IntCmp(void *elem1,void *elem2){ | |
int *ip1 = elem1; | |
int *ip2 = elem2; | |
return *ip1 - *ip2; | |
} |
我们再来举一个如果数组是字符串的例子
char * notes[] = {"Ab","F#","B","Gb","D"}; | |
char *favoriteNote = "Eb";\ | |
char **found = lsearch(&favoriteNote,notes,5,sizeof(char*),StrCmp); //&favoriteNote 是一个 char ** | |
int StrCmp(void *vp1,void *vp2){ | |
char *s1 = *(char**)vp1; // 强制转换为 char ** 再对其解引用 | |
char *s2 = *(char**)vp2; | |
return strcmp(s1,s2); //clib 中自带的一个字符一个字符的比较 | |
} |
上述例子中,为何不直接将 vp 强制转换为 char * 类型的呢?因为我们的 notes 数组实际上相当于 char**,于是我们知道实际上 vp 与我们的字符串 "Ab" 之类的有两跳的距离,对 vp 解一次引用我们能得到的是指向字符串的首地址,再解一次引用得到的是字符串的首字符。strcmp 函数需要的是字符串的首地址,所以我们对 vp 强制转换为 char**,再解一次引用即可。如果直接使用 (char*) vp1,系统就会误把存储着字符串的地址认为是字符串,所以不能够直接强制转换为 char*。
favoriteNote 是一个 char * 类型的变量,&favoriteNote 是一个 char ** 类型的变量,当然也可以传入 favoriteNote,但是这样就破坏了函数变量处理的对称性,因为在之后的处理中,我们的 vp 都是 char ** 进行处理的,而 favoriteNote 按 char * 进行处理。
# 实现一个栈 Stack.h
typedef struct{ | |
int *elems; | |
int logicalLen; // 已经使用的内存 | |
int alloclength; // 申请的内存大小 | |
}stack; | |
void StackNew(stack *s); | |
void StackDispose(stack *s); | |
void StackPush(stack *s,int value); | |
int StackPop(stack *s); |
上述的结构是 12 字节的,并且都是隐式的 public,但是我们要将其当作黑盒来处理,使用外在的函数对结构进行操作。
当执行下面代码时,c 会为你保留一部分内存空间,但不会像 java 那样将内存空间清 0。
stack s; |
假设,当我们使用 StackNew (&s); 时,系统会预申请一个能存入 4 个 int 的大小空间,这时进行任何操作都是非常迅速的,因为空间已经提前申请好了;当存入的数超过 4 个时,系统会再申请一个翻倍的空间,并把原先空间中的内容搬过来,原先空间删除。
下面实现一部分内容:
s
是一个局部变量,它假设的是它指向的是一个 12 字节的内存空间,并且内容未知。
void StackNew(stack &s){ | |
s->logicallen = 0; | |
s->allocLen = 4; | |
s->elems = malloc(4*sizeof(int)); // 动态分配内存函数,返回这一大块内存地址的开始地址 | |
assert(s->elems != NULL); // 如果 assert 里面的内容为 false,assert 会终止程序,并告知终止位置 | |
} |