指針
- 指針是一種保存變量地址的變量。
指針是能夠存放一個地址的一組存儲單元(通常是兩個或者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;
}