指針與數組(筆記)

指針

  • 指針是一種保存變量地址的變量
  • 指針是能夠存放一個地址的一組存儲單元(通常是兩個或者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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章