1指针
int x = 1, y = 2, z[10];
int *ip; //ip是指向int类型的指针
ip = &x; //ip现在指向x
y = *ip; //y的值现在为1
*ip = 0; //x的值现在为0
ip = &z[0]; //ip现在指向z[0]
每个指针都必须指向某种特定的数据类型(一个例外情况是指向void类型的指针可以存放指向任何类型的指针,但它不能间接引用其自身。)
*ip = *ip + 10; 一元运算符*和&的优先级比算术运算符的优先级高。
*ip += 1 等同于 ++*ip 或 (*ip)++
其中(*ip)++的括号是必须的,否则将对ip进行加一,因为类似于*和++这样的一元运算符遵循从右往左的结合顺序。
若想直接修改主调函数中的变量的值可以用指针参数,例如
void swap(int *px, int *py)
{
}
swap(&a, &b);
2.指针与数组
通过数组下标所能完成的任何操作都可以通过指针来实现,而且速度更快。
int a[10];
int *pa;
pa = &a[0]; //指向a[0] 也可以写成pa = a;
pa+i 指向a[i],*(pa+i)引用的是数组元素a[i]的内容
a[i]可以写成*(a+i),在计算数组a[i]的值得时候,C语言实际先将转换成*(a+i)形式。
&a[i]和a+i的含义也是相同的。
但是,数组名和指针之间有一个不同之处是,指针是一个变量,pa=a和pa++都是合法的,数组名不是变量,因此类似a=pa和a++形式的语句是非法的。
把数组名传递给一个函数时,实际传递的是该数组第一个元素的地址,数组名参数必须是一个指针,也就是一个存储地址值的变量。
int strlen(char *s)
{
int n;
for(n = 0; *s != '\0'; s++)
n++;
return n;
}
strlen("hello world"); //字符串常量
strlen(array); //字符数组array
strlen(ptr); //ptr指向char类型的指针
上面的都可以正确执行。
在函数定义中,char s[]; 和 char *s 是等价的。
插一道,
char a1[] = {'k', 'o', 'b', 'e'}; //错误,出现乱码 strlen(a1) = 11;
char a1[] = {'k', 'o', 'b', 'e', '\0'}; //正确 strlen(a1) = 4;
char a2[4] = "kobe"; //错误 数组界限溢出
char a2[5] = "kobe"; //正确 strlen(a2) = 4
在字符串的内部表示中,字符数组以字符'\0'结尾。字符串常量占据的存储单元数也比引号内的字符数大1。
3.地址算术运算
C语言保证,0永远不是有效的数据地址,因此,返回0可用来表示发生了异常事件。
指针与整数之间不能相互转换,但0是惟一的例外:常量0可以赋值给指针,指针也可以和常量0进行比较。
如果指针p和q指向同一个数组的成员,那么他们之间就可以进行==、!=、<、>=的关系比较运算。(指针的算术运算中可使用数组最后一个元素的下一个元素的地址)、
指针可以与整数相加减
int strlen(char *s)
{
char *p = s;
while(*p != '\0')
p++;
return p-s;
}
4.
strcmp函数,根据s按照字典顺序小于、等于或大于t的结果分别返回负整数、0或正。
//数组实现
int strcmp(char *s, char *t)
{
int i;
for(int i = 0; s[i] == t[i]; i++)
if(s[i] == '\0')
return 0;
return s[i] - t[i];
}
//指针实现
int strcmp(char *s, char *t)
{
for( ; *s == *t; s++, t++)
if(*s!='\0')
return 0;
return *s-*t;
}
5.指针数组的声明:char *lineptr[MAXLINES];具体使用可尝试写readlines函数。
6.在C语言中,二维数组实际上是一种特殊的一维数组,它的每个元素也是一个一维数组。数组元素按行存储,因此当按存储顺序访问数组时,最右边的数组下标变化得最快。
函数的参数声明中必须指明数组的列数,与行数没有太大关系:
f(int daytab[2][3]){} 也可以写成f(int daytab[][13]) {} 还可以写成f(int (*daytab)[13])
因为[]优先级高于*,所以必须使用圆括号。
除数组的第一维下标可以不指定大小外,其余各维都必须明确指定大小。
7.指针与多维数组
int a[10][20];
int *b[10];
区别,二维数组a分配了200个int类型长度的存储空间,对b来说仅仅分配了10个指针,并且没有对它们初始化,若b每个元素指向20个元素数组,那么分配200个int长度存储空间以及10个指针存储空间。指针数组一个优点在于数组的每一行长度可以不同,也就是说b的每个元素不必都指向20个元素的向量,某些可以2个,某些可以1个,某些也可以不指向任何向量。
8.命令行参数
调用主函数main时,它带有两个参数,argc用于参数计数,表示运行程序时命令行中参数的数目;第二个参数argv用于参数向量,是一个指向字符串数组的指针,其中每个字符对应一个参数。
按C语言的约定,argv[0]的值是启动该程序的程序名,因此argc的值至少为1。如果argc的值为1,说明程序名后面没有命令行参数。最后一个参数是argv[argc-1],另外ANSI标准要求argv[argc]的值必须为一个空指针。
9.类型定义 typedef
tyepdef int Length; Length len,a,b,c;
typedef struct tnode
{
char *word;
int count;
} Treenode;
typedef声明并没有创建一个新类型,只是为某个已存在的类型增加了一个名称而已。
10.联合是可以在不同时刻保存不同类型和长度的对象的变量,编译器负责跟踪对象的长度和对齐要求。联合提供了一种方式,以在单块存储区中管理不同类型的数据,而不需要再程序中嵌入任何同机器有关的信息。
union u_tag{
int ival;
float fval;
char *sval;
}u;
变量u必须足够大,以保存这3种类型中最大的一种,具体长度同具体的实现有关。
过早退出是一切失败的根源------高德纳