1、二维(多维)数组
多维数组定义
float y[4][3]; //4行3列
二维数组可以看作是一个元素为另一个一维数组的一维数组;
三维数组可以看作元素为二维数组的一维数组…
因此,在C语言中,下标变量应写作:y[i][j],而不能写成:y[i, j]
多维数组的初始化
int y[4][3] = {
{ 1, 3, 5 },
{ 2, 4, 6 },
{ 3, 5, 7 },
};
存储情况如下:
int y[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 }; 也同上,因为在C语言中,数组元素按行存贮。
多维数组使用
如果把一个二维数组作为参数,则在函数定义中,形参数组的说明中必须指明列的数目,而行的数目可空着不写。
如:
main( )
{
float a[4][3], b[3][4], c[4][4];
fun(a, 4, b , 3 , c, 4);
}
void fun(float x[ ][3],int rowx, float y[ ][4],int rowy, float z[ ][4], int rowz)
{
}
2、指针
指针是一种数据类型;
指针变量:存放的是所指对象的地址
在C语言中,允许指针指向任何类型的对象(可指向基本类型、构造类型),甚至可指向其它指针或指向函数。
指针赋值
通过&(取地址运算符)使指针指向某个对象
int i = 100;
int *pi;
pi = &i;
通过指向同一数据类型的指针赋值
double i, *pi, *pj;
i = 10.24;
pi = &i;
pj = pi;
唯一可以赋给指针的整数值:0,表示空指针,一般写成常量NULL
指针可以在程序运行的不同时刻指向不同的对象
通过 * 一元运算符(解寻址或解引用运算符)取得指针所指向的数据值
int i = 10, y = 20, *pi;
pi = &i;
y = *pi;
当pi指向具体对象y时,*pi为pi所指对象的值,以后凡是对y的引用,都可用*pi来代替
3、可以通过将指针作为函数参数来改变多个变量的数据,如下:
void swap ( int *px, int *py) //形参定义为指针
{
int temp;
temp = *px;
*px = *py;
*py = temp;
}
main( )
{
int a =2, b = 3;
swap ( &a, &b); //实参传递的是变量的地址
}
关于指针的一些说明:(无小括号时,右结合)
4、动态内存管理(malloc与free)*
在C中可以使用标准库函数malloc动态为指针变量申请一块内存空间(初始化指针变量)
void * malloc ( unsigned int size );
使用malloc初始化指针变量的常见用法:
char *s; int *intptr;
s = (char *)malloc(32); /* s指向大小为32个字节(字符)的空间*/
s = (char *)malloc(strlen(p)+1); /* s指向能正好存放字符串p的空间*/
intptr = (int *)malloc(sizeof(int)*10);/* ptr指向能存放10个整型元素的空间*/
使用malloc申请到的动态空间在不用时应使用函数free释放。如,free(s);
使用malloc和free函数要用:#include <stdlib.h>
运算符sizeof用来计算所在系统中某种类型或类型变量所占的长度(以字节为单位)。如:
sizeof(int),sizeof(n),sizeof(double)
具体值取决于系统,通常int或int变量长度为4,double为8
5、指针应具有非零(无符号整数)值,如将0(通常**#define NULL 0**)赋给予指针,则该指针没有指向任何具体对象,即空指针。
6、在C语言中,数组的名字就是指向该数组第一个元素(下标为0)的指针,即该数组第一个元素的地址,也即数组的首地址
7、当指针指向某一数组时:
a、指针和整数可以进行加减。(使用指针访问数组)
若p为指针,则p+n和p-n是合法的,同样p++也是合法的,它们的结果同指针所指对象类型相关。
pi = a;
pi++; //这时pi指向a[1],*pi为a[1]
pi+=6; //这时pi指向a[7],*pi为a[7]
b、两个指向同一类型的指针,可进行= = , > , <等关系运算,其实就是地址的比较。
if ( pi==pj ) 用来判断pi是否超出了数组表示的范围
c、两个指向同一数组成员的指针可进行相减
如, pj-pi表示数组的长度
d、当P1,和P2指向同一类型时,可以进行赋值
如:py = px,则px,py指向同一对象。
8、两指针不能相加!!!!!
如图,计算中间指针,不能写成 mid = (low + high ) /2,应写成 mid = low + (high – low)/2
9、几对指针的区别:
a、 p++和p+1的区别
p++结果为p指向下一元素;p+1结果为下一元素的指针,但p本身不变。
b、y = *px + 1和y= *(px + 1)的区别
*px+1为取px所指对象内容加1 ;*(px+1)为px指针加1,并取结果指针所指对象内容;
c、y = (*px)++和y = *px ++的区别
(*px)++为先取px所指对象内容进行运算,然后对其加1;*px++为先取px所指对象内容进行运算,然后指针px加1。(*p++等价于*(p++),*和++同优先级,右结合)
如下图:
10、常用标准字符串库函数
#include <string.h>
int strlen(char s[ ]);
char *strcpy(char s[ ], char t[ ]);
char *strcat(char s[ ], char t[ ]); //字符串连接
int strcmp(char s[ ], char t[ ]);
//s为结果
11、数组名和指针
int a[10], x;
int *pa;
pa =a;
一般有:a[i] , *(pa+i) , *(a+i) 代表同一数据
但特别注意:数组名和指针(变量)是有区别的,前者是常量,而后者是变量
因此,尽管我们可写pa =a;
但决不能写:a = pa ; a++; 等。
12、为什么使用指针?
- 扩展了语言的功能,如通过传递指针来修改实参变量、或通过返回指针来返回数组等;
- 能够更方便的组织和操作数据,如,离散数据的组织和访问(链表,树等);
13、指针与字符串常量
对于字符串常量,可以把它看成一个无名字符数组,C编译程序会自动为它分配一个空间来存放这个常量,字符串常量的值是指向这个无名数组的第一个字符的指针,其类型是字符指针。
所以,printf(“a constant character string\n”); 传递给函数的是一个无名数组第一个字符的指针。
注意:字符数组和字符指针使用时容易混淆,如下:
14、指针数组
指针数组就是由指针组成的数组,即该数组的每一个元素都是指向某一对象的指针;
指针数组与二维数组的区别:
a、尽管二维字符数组与字符指针数组在存储形式上不同,但它们在初始化形式以及访问元素方式上却是相同的。
例如,无论是指针数组,还是二维数组,下面两种形式访问的都是同一个元素,结果都是字符串”Friday”中的字符’y’。
*(days[5]+5) , days[5][5]
b、使用指针数组来存放不同长度的字符串可以节省存贮空间。
15、一些分析!!!!
#include <stdio.h>
char a[4][5] = { "abcd", "efgh", "ijkl", "mnop" };
main( )
{
printf("a=%x, a[0]=%x, &a[0][0]=%x\n", a, a[0], &a[0][0]);
printf("a+1=%x, a[0]+1=%x, &a[0][1]=%x\n", a+1, a[0]+1, &a[0][1]);
printf("**(a+1)=%c, *(a[0]+1)=%c\n", **(a+1), *(a[0]+1));
}
二维数组a如下图:
运行结果如下:
16、类型定义(typedef)
类型定义的语法格式为:
typedef 原类型名 新类型名;(别忘了分号)
如:
typedef int LENGTH;
typedef char * STRING;
变量说明为:
LENGTH len, maxlen;
STRING ps,lineptr[LINES];
这与如下直接说明等价:
int len, maxlen;
char * ps, * lineptr[LINES];
定义数组类型:
typedef int VECT [100];
typedef double MAT [5][5];
VECT v1,v2;
MAT m1,m2;
相当于:
int v1[100], v2[100];
double m1[5][5], m2[5][5];
必须强调,typedef说明均不产生新的数据类型,也不定义存储单元,它只是给已有的类型又增添了新的类型名,没有产生新的语义,即用这种方法所说明的变量与明确指出说明的那些变量有相同的性质。
类型定义的必要性:
- 将程序参数化,便于移植;
- 为程序提供较好的说明信息,便于理解;
类型定义的一个常见用法是用来定义结构类型,如下:
typedef struct {
int day;
int month;
int year;
char week_name[4];
} DATE;
DATE d, *pd, ad[10];
//使用typedef定义结构类型名后,结构变量的定义(或说明)就更简洁了。
17、结构体成员的引用
a、结构名 . 成员名
b、结构指针 -> 成员名
pd->year与(*pd).year 是完全等价的,这是由于在C语言中指向结构的指针使用非常频繁,特为此设立了一个新运算符(->)。
18、当数组中的每一个元素都是同一结构类型的变量时,则称该数组为结构数组。
例如: struct person table[100];
19、结构与联合(union,共用体)的异同
- 在定义或说明形式上,union和struct很类似,但在任何时刻联合只允许联合中说明的某一成员留在联合里。
- 结构由多个成员(分量)所组成,而联合只有一个成员,只不过该成员的名字和类型可以在规定的几个里选定一个。
- 因此,联合可以看作是一个特殊的结构,其所有成员在结构中的位移量都是0,当对联合变量分配存贮空间时,应保证它能容纳最大的一个成员的大小,而存贮空间的边界应能适于联合中的所有可选成员的类型。
- 对联合的初始化只能对应于它的第一个可选成员。
- 对联合成员的引用方式完全和结构的情况一样。