指针
- 指针是一种保存变量地址的变量。
指针是能够存放一个地址的一组存储单元(通常是两个或者4个)。
通常的机器都有一些列连续编号或编址的存储单元,这些单元可以单个操纵,也可以以连续成组的方式操纵。char占一个字节,short占两个连续字节。
一元运算符&用来取一个对象的地址。地址运算符&只能应用于内存中的对象,即变量与数组元素;不能作用于表达式、常量或register类型的变量。
例如:p = &c (把c的地址赋值给变量p,把p称为“指向”c的指针)
一元运算符*是间接寻址或间接引用运算符。当它作用于指针时,将访问指针所指向的对象。
int x = 1, y = 2, z[10];
int *ip; //是一个指向int类型的指针。
ip = &x; //ip指向x
y = *ip; //y=1
*ip = 0; //x=1
ip = &z[0] //ip指向z[0]
- 类似于int *ip的声明方式也可以声明函数。
double *dp, atof(char *) //这句代码声明了一个double类型的指针dp,还声明了一个返回值为double类型的函数。
- 一元运算符&和*的优先级比算数运算符的优先级要高。
y = *ip + 1 //这句话的意思是把*ip指向的对象的值取出并加1,然后再将结果赋给y。
++*ip与(*ip)++等价//一元运算符从右到左
(*ip)++中的()如果被去掉,表达式将对指针ip进行加一运算,而不是对ip指向的对象进行加1运算,这是因为类似于*和++这样的一元运算符遵循从右到左的结合顺序。
- 指针与函数参数,指针参数使得被调用函数能够访问和修改主调函数中对象的值。
c语言是以传值的方式将参数值传递给被调用函数,即值传递。例如下面这个swap函数是用来交换两个变量次序的元素。是无法达到目的的。
#include <stdio.h>
void swap(int x,int y);
int main(void) {
int a = 1;
int b = 2;
swap(a,b);
printf("%d",a);
printf("%d",b);
}
void swap(int x,int y){
int temp;
temp = x;
x = y;
y = temp;
printf("%d",x);
printf("%d",y);
}
修改过的swap函数可以实现该功能。
#include <stdio.h>
void swap(int *px,int *py);
int main(void) {
int a = 1;
int b = 2;
swap(&a,&b);
printf("%d",a);
printf("%d",b);
}
void swap(int *px,int *py){
int temp;
temp = *px;
*px = *py;
*py = temp;
printf("%d",*px);
printf("%d",*py);
}
数组
- 数组名所代表的就是该数组最开始的一个元素的地址。
void array1(){
int a[10]; //定义一个长度为10的数组
int *pa; //定义一个整型的指针
pa = &a[0]; //指针指向第一个元素
int x = *pa;
int y = *(pa+1);
pa = a;//等价于pa = &a[0]
a[i]//等价于*(a+i)
}
- c语言在计算数组元素a[i]的值,实际上是将其转换为*(a+i)的形式,然后再求值。
- 数组名和指针之间有一个不同之处,指针是一个变量。pa = a和pa++都是合法的。但是数组名不是变量,因此。类似于a=pa和a++形式的语句是非法的。
int strlen(char *s);
void main(){
char strArray [5] = {'a','b','c','d','e'};
char *pc = "abcde";
printf("%d",strlen("abcde"));//字符串常量
printf("%d",strlen(strArray));//字符数组
printf("%d", strlen(pc));//pc是一个指向char类型的指针
}
//strlen函数,获取字符串长度
int strlen(char *s){
int n;
for(n = 0; *s != '\0'; s++){
n++;
}
return n;
}
在函数定义中,以下两种形式参数等价:
char s[];//这种情况函数可以根据情况判定是按照数组处理还是指针处理,随后根据相应的方式操作参数。
char *s;
在函数调用时,以下两种形式等价:
//这两种都是把起始于a[2]的子数组的地址传递给函数f
f(&a[2])
f(a+2)
//在函数f的参数声明形式可以为:
f(int arr[]){}
f(int *arr){}
- 数组不能越界。
关于指针的有效运算
- 指针与整数之间的加法或减法运算。
- 指向相同数组中元素的两个指针间的减法或比较运算。
- 将指针赋值为0或指针与0之间的比较运算。
字符指针与函数
- 字符串常量是一个字符数组,字符串常量占据的存储单元比双引号内的字符数大1(以空字符\0结尾)。
"I am a string"
- 函数的参数在接受一个字符串时,接受的是一个指向字符数组第一个字符的指针。
printf("hello,world");
- 字符串赋值,把一个指向该字符数组的指针赋值给pmessage。
char *pmessage;
pmessage = "hello world";
实现将指针t指向的字符串复制到指针s指向的位置
- 指针方式实现
#include <stdio.h>
void strcpy(char *s,char *t);
void main() {
char px = "aa";
char py = "";
printf(py);
strcpy(py,px);
printf(py);
}
void strcpy(char *s,char *t){
int i;
i = 0;
while((s[i] = t[i]) != '\0')
i++;
printf("%d",i);
}
指针数组——给不定长的字符串排序
- 读取所有的输入行:输入函数必须收集和保存每个文本行中的字符,并建立一个指向这些文本行的指针的数组。同时还要统计输入的行数,排序打印时要用。
- 输出函数只需要按照指针数组中的次序依次打印这些文本即可。
#include <stdio.h>
#include <string.h>
#define MAXLINES 3 //最大行数
char *lineptr[MAXLINES]; //定义一个字符指针数组
int readlines(char *lineptr[],int nlines); //输入函数声明
void writelines(char *lineptr[],int nlines);//输出函数声明
void qsort(char *lineptr[],int left,int right);//排序函数声明
main(){
int nlines;
if((nlines = readlines(lineptr,MAXLINES)) >= 0){//读
qsort(lineptr,0,nlines-1);//排序
writelines(lineptr,nlines);//输出
return 0;
} else{
printf("error : input too big to sort\n");
return 1;
}
}
#define MAXLEN 1000
int getlines(char s[],int);
char *alloc(int);
//获取一行字符串放到s[]中,并返回长度
int getlines(char s[],int lim){
int c,i;
for(i=0; i<lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
s[i] = c;
if(c=='\n'){
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
//将读取到的输入行,放到lineptr数组中
int readlines(char *lineptr[],int maxlines){
int len,nlines;
char *p,line[MAXLEN];
nlines = 0;
int i =0;
while ((len = getlines(line,MAXLEN))>0){//如果输入的一行字符串的长度大于0,则进入循环
if(nlines >= maxlines || (p = alloc(len)) == NULL)//如果行数已经大于最大行数,或者存储空间不足,返回-1
return -1;
else{
line[len-1]='\0';//去掉行尾的换行符
strcpy(p,line);//将line数组的字符复制到p指向的内存。
lineptr[nlines++] = p;//将每一行的字符指针赋值给字符指针数组lineptr的每一个位置。
}
i++;
if (i>=MAXLINES){//如果循环次数大于最大行数,立即返回
return nlines;
}
}
printf("error : input too big to sortAAAAAA\n");
return nlines;
}
//写输出行
void writelines(char *lineptr[],int nlines){
int i;
for(i = 0; i<nlines; i++){
printf("%s\n",lineptr[i]);
}
}
//排序
void qsort(char *v[],int left,int right){
int i,last;
void swap(char *v[],int i,int j);
if(left >= right)
return;
swap(v,left,(left + right)/2);
last = left;
for(i = left + 1; i <= right; i++){
if(strcmp(v[i],v[left])<0)
swap(v,++last,i);
}
swap(v,left,last);
qsort(v,left,last-1);
qsort(v,last+1,right);
}
//交换v[i]和v[j]
void swap(char *v[], int i, int j){
char *temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
//申请一块长度为n的内存
#define ALLOCSIZE 10000
static char allocbuf[ALLOCSIZE];
static char *allcop = allocbuf;
char *alloc(int n){
if(allocbuf + ALLOCSIZE - allcop >= n){
allcop += n;
return allcop - n;
} else{
return 0;
}
}
多维数组
#include <stdio.h>
static char daytab[2][13] = {
{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31}
};
//将某年某月某日的日期表示形式转换为某年中的第几天的表示形式
int day_of_year(int year,int month,int day){
int i,leap;
leap = year%4 == 0 && year%100 != 0 || year%400 == 0;
for(i = 1; i < month; i++){
day += daytab[leap][i];
}
return day;
}
//将某年中的第几天转换成某月某日的表示形式。
void month_day(int year,int yearday,int *pmonth,int *pday){
int i,leap;
leap = year%4 == 0 && year%100 != 0 || year%400 == 0;
for(i = 1;yearday > daytab[leap][i]; i++)
yearday -= daytab[leap][i];
*pmonth = i;
*pday = yearday;
}
void main() {
printf("%d",day_of_year(2018,01,12));
}
二维数组和指针数组的区别
int a[10][20];
int *b[10];
- a分配了200个int类型长度的存储空间,b仅仅分配了10个指针。
- 指针数组的每个数组的长度可以不同。也就是说,b可以有的指向长度为2的数组,有的可以指向长度为20的数组。
- b的初始化必须以显示的方式进行,比如:静态初始化,或者代码初始化。
指向函数的指针
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void swap(char *v[],int i,int j){
char *temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
int compareTo(char i,char j){
if(i > j){
return 1;
} else if(i < j){
return -1;
} else{
return 0;
}
}
//正常排序函数
void qsort__(char *v[],int left,int right){
int i,last;
if(left >= right)
return;
swap(v,left,(left + right)/2);
last = left;
for(i = left + 1; i <= right; i++){
if(compareTo(v[i],v[left])<0){
swap(v,++last,i);
}
}
swap(v,left,last);
qsort__(v,left,last-1);
qsort__(v,last+1,right);
}
int main(int argc, char *argv[]){
char* arr2[6] = {'2','8','4','5','7','6'};
qsort__(arr2,0,5);
for(int i=0; i<6; i++){
printf("%c",arr2[i]);
}
}
修改版
//排序函数(指向函数的指针)
void qsort_(char *v[],int left,int right, int (*comp)(void*, void*)){
int i,last;
if(left >= right)
return;
swap(v,left,(left + right)/2);
last = left;
for(i = left + 1; i <= right; i++){
if((*comp)(v[i],v[left])<0){
swap(v,++last,i);
}
}
swap(v,left,last);
qsort_(v,left,last-1,comp);
qsort_(v,last+1,right,comp);
}
int main(int argc, char *argv[]){
char* arr2[6] = {'2','8','4','5','7','6'};
qsort_(arr2,1,4,(int (*)(void*,void*))(compareTo));
for(int i=0; i<6; i++){
printf("%c",arr2[i]);
}
}
求函数绝对值
int absolute(int number){
int i = number >> sizeof(number) * 8 - 1;
return (number ^ i) - i;
}