指针与数组(笔记)

指针

  • 指针是一种保存变量地址的变量
  • 指针是能够存放一个地址的一组存储单元(通常是两个或者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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章