@songpfei
2016-02-24T03:38:45.000000Z
字数 5933
阅读 2361
程序设计论著笔记
char a[9]="abcdefgh";... c=a[i]; char* p ... c=*p;,其高速编译器p是一个指针(在许多现代的机器里它是四个字节对象),它指向的对象是一个字节。为了取得这个字符,必须得到地址p的内容,把它作为字符的地址并从这个地址中取得这个字符。指针的访问要灵活的多,但要增加一次额外提取: | 序号 | 指针 | 数组 |
|---|---|---|
| 1 | 保存数据的地址 | 保存数据 |
| 2 | 间接访问数据,首先取得指针的内容,把它作为地址,然后从这个地址提取数据。如果指针有一个下标[i],就把指针的内容加i作为地址,从中提取数据 | 直接访问数据,a[i]只是简单的以a+i为地址取得数据 |
| 3 | 通常用于动态数据结构 | 通常用于存储固定数目且数据类型相同的元素 |
| 4 | 先关函数为malloc(),free() | 隐士分配和删除 |
| 5 | 通常指向匿名数据 | 自身即为数据明 |
注!注!注!
数组和指针都可以在他们的定义中使用字符串常量进行初始化,尽管看上去一样,但底层机制不一样。
定义指针时,编译器并不为指针所指向的对象分配空间,它只是分配指针本身的空间,除非在定义的同时赋给指针一个字符串常量进行初始化。
char *p="breadfruit";
注意只有对字符串常量才是如此。不能指望浮点数之类的常量分配空间,如:
float *pip=3.14;/*错误,无法编译通过*/
在ANSI C中,初始化指针所创建的字符串常量被定义为只读(存储在静态区)。如果试图通过指针修改这个字符串的值,程序出现未定义(出错)
数组也可以用字符串进常量进行初始化:
char a[]="gooseberry";
与指针相反,由字符串常量初始化的数组是可以修改的(存储在栈中)。其中单个字符在以后可以改变:
strncpy(a,"black",5);
tips:所有作为函数参数的数组名总是可以通过编译器转换为指针,且被当做指向该数组第一个元素的指针。
编译器只向函数传递数组的地址,而不是整个数组的拷贝,其实处于效率考虑。
所以,一下形式均合法,且最终被编译器转化为指针形似:
func(int* a);func(int a[]);func(int a[10]);
所以,在函数内部,使用sizeof(a)无法得到数组的大小,因为数组a[]在作 为形参时被自动转化为指针,所以sizeof(a)一般为4(存储指针的空间)
a[i]这样的形式对数组进行访问总是被编译器“改写”成或解释为像*(a+i)这样的指针访问。C语言中,定义和引用多维数组唯一的方法是使用数组的数组:
------------------------------------------------------------------
char carrot[10][20];//声明一个10*20的多维数组
或者声明可以看上去更像“数组的数组”形式
typedef char vegetable[20];
vagetable carrot[10];
不论哪种情况,访问单个字节都可以通过carrot[i][j]的形式,
编译器在编译时会把它解析为*(*(carrot+i)+j)的形式
------------------------------------------------------------------
tips:C语言的数组就是一维数组:
当提到C语言中的数组时,就把它看作是一种向量(vector),也就是某种对象的以为数组,数组的元素可以是另一个数组。
### 3.1 内存中数组的布局:
在C语言多为数组中,最右边的下标是最先变化的,这个约定被称为“行主序”.其实线性存储, a[i][j] 与 *(*(a+i)+j)等价
### 3.2 多维数组初始化:
int a[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
指针数组:
char *pea[4]; //一维指针数组,每个指针指向一个字符串,数组的每个元素内为一个char*指针
(注意区别:char(*pea)[4];数组指针,一个指向具有4个字符类型元素的数组)
可以进行如下初始化:
for (j=0;j<=4;j++)
pea[j]=malloc(6);
也可以一次性的用malloc分配整个数组:
malloc(row_size*column_size*sizeof(char));
软件信条:
对于s[i][j]这样形式的原型声明:
int s[2][3];/* int 型 二维 数组*/int *s[2]; /* int 指针数组,每个指针指向一个含有3个元素的以为一维数组*/int **s; /* 指向指针的指针*/int (*s)[3];/* 数组指针,一个指向为int数组(长度为3)的指针
都是由于作为左值的数组名本编译器当做指针。
锯齿状数组:
如果声明一个字符串指针数组,并根据需要为这些字符串分配内存,将会大大节省系统资源:
char* turnip[UMPTEEN]char my_string[]="your message here";/*贡献字符串*/turnip[i]=&my_string[0];/*拷贝字符串*/turnip[j]=malloc(strlen(my_string)+1);strcpy(turnip[j],my_string);
tips: p225
数组和指针参数被编译器的修改规则:
| 实参 | 所匹配的形参 | ||
|---|---|---|---|
| 数组的数组 | char c[2][3] | char(*)[3] | 数组指针 |
| 指针数组 | char *c[2] | char** | 指针的指针 |
| 数组指针(行指针) | char (*a)[3] | char (*a)[3] | 不改变 |
| 指针的指针 | char **a | char**a | 不改变 |
func(int array[10][20]); func(int array[][20]); func(int (*array)[20]);传递一个数组指针,数组的长度为20.func(int ** array);
//1. 数组声明int **array;array = (int **)malloc(m *sizeof(int *));for(i=0;i<M;i++)array[i] = (int *)malloc(n *sizeof(int));这时,在分配空间的作用域里,对0<=i<M,0<=j<N,array[i][j]的访问完全没有问题。那么,对应地,函数写作//2. 函数声明int func(int **array,int m,int n) {...printf("%d ", *(*(array+i)+j));...}值得注意的是,虽然malloc()每次分配的空间在地址上是连续的,但是多次malloc()分配的空间之间并不一定是连续的,这与在栈上分配的二维矩阵有着根本的不同,对于二维数组array[3][3],不能再用array[1][4]来访问array[2][1]了,前者地址越界。
#include <stdio.h>#include <stdlib.h>#include <assert.h>int func(int *array, int m, int n) {int i,j;for(i=0;i<m;i++) {for(j=0;j<n;j++)printf("\t%d",*(array+i*n+j));printf("\n");}return 0;}int main(int argc,char** argv) {int m,n,i;int *array;assert(argc == 3);m = atoi(argv[1]);n = atoi(argv[2]);array = (int*)malloc(m*n*sizeof(int));for(i=0;i<m*n;i++)array[i] = i;func(array,m,n);return 0;}
int quarters = 4;int regions = 5;double sales[quarters][regions]; //一个变长数组VAL
变长数组有一些限制:变长数组必须是自动存储类的,意味着它们必须在函数内部或作为函数参数声明,而且声明时不可以进行初始化。
C90不支持这种形式,C99支持,因此一些较新的编译器可以对下面的代码进行执行。注意print()的参数顺序不能改变。
void print(int x, int y, int a[x][y]){printf("\n");int i, j;for(i = 0; i < x; i++){for(j = 0; j < y; j++)printf("%d ", a[i][j]);printf("\n");}}// Function to initialize the two-dimensional arrayvoid init_2d(int *a, int x, int y){int i, j;for(i = 0; i < x; i++){for(j = 0; j < y; j++){a[i*y + j] = i + j;}printf("\n");}}int main(){int m , n ;scanf("%d %d",&m,&n);int a[m][n]; // a two dimensional whose size has been defined using variablesinit_2d(a, m, n);print(m, n, a);}
这段代码出自http://stackoverflow.com/questions/17181577/two-dimensional-arrays-in-c。
(2013.7.28更新)
另外,这种分配方式仍然是在栈上,相关讨论可见于http://bbs.csdn.net/topics/90350681。
void PrintArray(int **array, int m, int n){if (array == NULL || (*array) == NULL)return;printf("********打印二维数组**************\n");for (int i = 0; i < m; i++){for (int j = 0; j < n; j++)printf("%d ", array[i][j]);printf("\n");}}int main(){int M, N;printf("请输入二维数组的行和列,以空格隔开:\n");scanf("%d %d", &M, &N);int **array=NULL;//声明array[m][n] 二维数组array = (int**)malloc(M*sizeof(int*));if (array == NULL)return -1;for (int i = 0; i < M; i++){array[i] = (int*)malloc(N*sizeof(int));if (array[i] == NULL)return -1;}printf("请输入%d行%d列的二维数组\n",M,N);for (int i = 0; i < M; i++)for (int j = 0; j < N; j++)scanf("%d", &array[i][j]);PrintArray(array, M, N);for (int i = 0; i < M; i++){free(array[i]);array[i] = NULL;}free(array);array = NULL;free(NULL);system("pause");return 0;}
void Print(int* array, int m, int n){if (array == NULL)return;printf("********打印二维数组**************\n");for (int i = 0; i < m; i++){for (int j = 0; j < n; j++)printf("%d ", *(array+i*n+j));printf("\n");}}int main(){int M, N;printf("请输入二维数组的行和列,以空格隔开:\n");scanf("%d %d", &M, &N);int* array = (int*)malloc(M*N*sizeof(int));if (array == NULL)return -1;printf("请输入%d行%d列的二维数组\n", M, N);for (int i = 0; i < M; i++)for (int j = 0; j < N; j++)scanf("%d",array+i*N+j);Print(array, M, N);free(array);array = NULL;system("pause");return 0;}