在C里面, 将变量作为参数传递给函数时, 变量的值将拷贝给这个函数的形参. 而形参在程序执行时, 它的值是放在stack内存区域的.
stack区域在linux中有限制默认是10MB, 如下 :
那么如果变量存储的值超过10MB, 作为参数传递给函数, 这个程序将面临Segmentation fault的危险, 因为stack区域只有10MB, 已经放不下传递过来的值了.
[root@db-172-16-3-150 zzz]# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 204800
max locked memory (kbytes, -l) 50000000
max memory size (kbytes, -m) unlimited
open files (-n) 131072
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 131072
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
那么如果变量存储的值超过10MB, 作为参数传递给函数, 这个程序将面临Segmentation fault的危险, 因为stack区域只有10MB, 已经放不下传递过来的值了.
如下 :
系统的stack限制为10MB.
修改stack的限制, 改成100MB, 再次执行, 将不会报错. 只是程序运行会比较慢, 因为要拷贝99MB到stack里面.
[root@db-172-16-3-150 zzz]# ulimit -s
10240
[root@db-172-16-3-150 zzz]# cat a.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
typedef struct big {
char a[99999999];
} big;
int test1(big b) {
fprintf(stdout, "this is test function.\n");
fprintf(stdout, "sizeof(b):%lu\n", sizeof(b));
//fprintf(stdout, "&b:%p\n", &b); // 这几行注释的代码都将带来Segmentation fault的结果. 因为99MB显然在stack是放不下的.
//fprintf(stdout, "b.a:%s\n", b.a);
//b.a[0] = 'b';
//fprintf(stdout, "b.a:%s\n", b.a);
return 0;
}
int main() {
big * b1 = malloc(sizeof(big));
b1->a[0]='a';
fprintf(stdout, "b1->a:%s\n", b1->a);
test1(*b1);
fprintf(stdout, "b1->a:%s\n", b1->a);
free(b1);
return 0;
}
结果 :
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./a.c -o a && ./a
b1->a:a
this is test function.
sizeof(b):99999999
b1->a:a
注释去掉后
//fprintf(stdout, "&b:%p\n", &b);
//fprintf(stdout, "b.a:%s\n", b.a);
//b.a[0] = 'b';
//fprintf(stdout, "b.a:%s\n", b.a);
结果报错 :
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./a.c -o a && ./a
Segmentation fault
修改stack的限制, 改成100MB, 再次执行, 将不会报错. 只是程序运行会比较慢, 因为要拷贝99MB到stack里面.
正因为是值拷贝, 所以在函数内部修改的b, 实际上b1 是没有修改的.
如果要通过函数来修改外部变量的值, 一个比较常用的方法是传递指针进来. 不管是直接指向变量的指针, 还是间接指向的.
[root@db-172-16-3-150 zzz]# ulimit -s 102400
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./a.c -o a && ./a
b1->a:a
this is test function.
sizeof(b):99999999
&b:0x7fff85608d50
b.a:a
b.a:b
b1->a:a
如果要通过函数来修改外部变量的值, 一个比较常用的方法是传递指针进来. 不管是直接指向变量的指针, 还是间接指向的.
接下来进入重点了, qsort就是一个会修改外部变量的函数, 它用的也是传递指针的方法来做到的.
例如传递一个array 变量(array 变量名是一个指针, 表示array的第一个元素的首地址.) 给qsort, 对这个array进行排序, 实际上已经改变了这个array存储的数值的顺序.
1. qsort需要知道
array在内存中的首地址.
2. qsort需要知道array中存储的每个元素的大小, 因为需要做值的交换 .
3. 同时qsort需要知道这个array有多少个元素, 这样才能算出array在内存中的结束位置.
4. 最后qsort需要一个compare函数, 用来比较array中任意两个元素的大小,
5. compare 函数的接口函数必须定义成这样的, 返回值int, 参数const void * :
int(*compar)(const void *, const void *)
如compare(a, b)当返回值=0, 表示a=b, 返回值>0表示a>b, 返回值<0表示a<b;
在这里a和b是指向array中元素的指针. 如int a[10]这个数组, a+0, a+1 ...... ; char * a[10]这个数组也一样 , a+0, a+1.....
因此在比较多维数组时需要考虑这个问题. 传入的到底是个啥地址?
例1 :
int a[]
例2 :
[root@db-172-16-3-150 zzz]# cat a.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int compare_int(const void * a, const void * b) {
int la = * ((int *)a);
int lb = * ((int *)b);
return (la - lb);
}
int main() {
unsigned int i;
int a[5] = {100, 9, 99, 67, 10};
qsort(a, sizeof(a)/sizeof(int), sizeof(int), compare_int);
for (i=0; i<(sizeof(a)/sizeof(int)); i++) {
fprintf(stdout, "a[%i]:%i\n", i, a[i]);
}
return 0;
}
结果 :
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./a.c -o a && ./a
a[0]:9
a[1]:10
a[2]:67
a[3]:99
a[4]:100
例2 :
char * a[]
[root@db-172-16-3-150 zzz]# cat a.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int compare_char(const void * a, const void * b) {
char ** la = (char **)a;
char ** lb = (char **)b;
return strcmp(*la, *lb);
}
int main() {
unsigned int i;
char *a[5] = {"digoal", "linux", "hello", "world", "postgresql"};
qsort(a, sizeof(a)/sizeof(char *), sizeof(char *), compare_char);
for (i=0; i<(sizeof(a)/sizeof(char *)); i++) {
fprintf(stdout, "a[%i]:%s\n", i, a[i]);
}
return 0;
}
结果 :
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./a.c -o a && ./a
a[0]:digoal
a[1]:hello
a[2]:linux
a[3]:postgresql
a[4]:world
例3 :
char a[][]
注意这里在传递地址的时候, 发生了array特征信息丢失.
因为二维数组的a, *a是一样的, 但是在传递进去后a和*a已经不一样了 . 所以在转换的时候不能使用char ** .而应该使用char *
【参考】
[root@db-172-16-3-150 zzz]# cat a.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int compare_char(const void * a, const void * b) {
char * la = (char *)a;
char * lb = (char *)b;
return strcmp(la, lb);
}
int main() {
unsigned int i;
char a[5][20] = {"digoal", "linux", "hello", "world", "postgresql"};
qsort(a, 5, 20, compare_char);
for (i=0; i<5; i++) {
fprintf(stdout, "a[%i]:%s\n", i, a[i]);
}
return 0;
}
结果 :
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./a.c -o a && ./a
a[0]:digoal
a[1]:hello
a[2]:linux
a[3]:postgresql
a[4]:world
【参考】
char *, char *[], char [][]的区别参考
http://blog.163.com/digoal@126/blog/static/163877040201271195312138/
[root@db-172-16-3-150 zzz]# man qsort
QSORT(3) Linux Programmer’s Manual QSORT(3)
NAME
qsort - sorts an array
SYNOPSIS
#include <stdlib.h>
void qsort(void *base, size_t nmemb, size_t size,
int(*compar)(const void *, const void *));
DESCRIPTION
The qsort() function sorts an array with nmemb elements of size size. The base argument points to the start of
the array.
The contents of the array are sorted in ascending order according to a comparison function pointed to by com-
par, which is called with two arguments that point to the objects being compared.
The comparison function must return an integer less than, equal to, or greater than zero if the first argument
is considered to be respectively less than, equal to, or greater than the second. If two members compare as
equal, their order in the sorted array is undefined.
RETURN VALUE
The qsort() function returns no value.
CONFORMING TO
SVr4, 4.3BSD, C99.
NOTE
Library routines suitable for use as the compar argument include strcmp() (see below), alphasort(), and ver-
sionsort().
EXAMPLE
For one example of use, see the example under bsearch(3).
Another example is the following example program, which sorts the strings given in its command-line arguments:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
static int
cmpstringp(const void *p1, const void *p2)
{
/* The actual arguments to this function are "pointers to
pointers to char", but strcmp() arguments are "pointers
to char", hence the following cast plus dereference */
return strcmp(* (char * const *) p1, * (char * const *) p2);
}
int
main(int argc, char *argv[])
{
int j;
assert(argc > 1);
qsort(&argv[1], argc - 1, sizeof(char *), cmpstringp);
for (j = 1; j < argc; j++)
puts(argv[j]);
exit(EXIT_SUCCESS);
}
SEE ALSO
sort(1), alphasort(3), strcmp(3), versionsort(3)
2003-11-15 QSORT(3)