天天看點

12.C語言-指針2

作者:數字雙碳王亮

指針引用多元數組

#include<stdio.h>

void main() {
  int a[3][4] = {
    {1,2,3,4},
    {5,6,7,8},
    {9,10,11,12}
  };

  //二維數組名,指向一維數組a[0],即0行首位址
  printf("%p\n", a);

  //0行0列元素位址
  printf("%p\n", a[0]);
  printf("%p\n", *a);

  //1行首位址
  printf("%p\n", a+1);

  //1行0列元素的位址
  printf("%p,%p\n", a[1],*(a+1));
}
           

*(a+i) 和 a[i] 是等價的

void main() {
  int a[3][4] = {
    {1,2,3,4},
    {5,6,7,8},
    {9,10,11,12}
  };

  printf("%d\n", *(*a+3));//4

  printf("%d\n",*(*(a+1)));//5

  printf("%d,%d\n", *a[2],*(*(a+2)));//9,9
}
           

用指向數組元素的指針變量輸出二維數組各元素的值

void main() {
  int a[3][4] = {
  {1,2,3,4},
  {5,6,7,8},
  {9,10,11,12}
  };

  int* p;

  for (p = a[0]; p < a[0]+12; p++)
  {
    if (p!=a[0] && (p - a[0]) % 4 == 0) {
      printf("\n");
    }
    printf("%4d", *p);
  }
}
           

通過使用者輸入确定元素的值

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

void main() {
  int a[3][4] = {
    {1,2,3,4},
    {5,6,7,8},
    {9,10,11,12}
  };
  int x, y;
  scanf("%d,%d", &x, &y);
  printf("(%d,%d)=%d\n",x,y,a[x][y]);
  printf("(%d,%d)=%d\n",x,y,*(*(a+x)+y));
}
           

3個學生,各學4門課,計算總平均分數以及第n個學生成績

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

void showscore();
void average();

void main() {
  float score[3][4] = { {65,67,70,60}, {80,87,90,81},{90,99,100,98} };
  average(*score, 12);
  printf("\n");
  showscore(*score, 1);
}

//計算平均數
void average(float* p, int n) {
  float sum = 0, avg = 0;
  float* p1;
  for (p1 = p; p1 < p + n; p1++)
  {
    sum += *p1;
  }
  avg = sum / n;
  printf("平均數:%f", avg);
}

void showscore(float* p, int n) {
  float* p1 = p + n * 4;//确定第幾個學員
  for (int i = 0; i < 4; i++)
  {
    printf("%5.2f ", *(p1 + i));
  }
}
           

周遊數組

形式參數是一個已定義大小的數組

void main() {
  float score[3][4] = { {65,67,70,60}, {80,87,90,81},{90,99,100,98} };
  //average(*score, 12);
  //printf("\n");
  //showscore(*score, 1);
  sum1(score);
}

void sum1(float num[12]) {
  double sum = 0;
  for (size_t i = 0; i < 12; i++)
  {
    sum += num[i];
  }
  printf("%f", sum);
}

           
void main() {
  float score[3][4] = { {65,67,70,60}, {80,87,90,81},{90,99,100,98} };
  sum2(score);
}

void sum2(float num[3][4]) {
  double sum = 0;
  for (int i = 0; i < 3; i++)
  {
    for (int j = 0; j < 4; j++)
    {
      sum += num[i][j];
    }
  }
  printf("%f", sum);
}
           

嵌套for

void average1(float* p) {
  float sum = 0, avg = 0;
  float* p1 = p;
  for (int i = 0; i < 3; i++)
  {
    p1 = p + (i) * 4;
    for (int j = 0; j < 4; j++)
    {
      printf("%5.2f ", *(p1 + j));
    }
    printf("\n");
  }
}
           

傳入一維數組指針

void main() {
  float score[3][4] = { {65,67,70,60}, {80,87,90,81},{90,99,100,98} };
  sum3(score);
}

//二維數組的指針就是一個指向一維數組的指針
void sum3(float (*p)[4]) {
  for (int i = 0; i < 3; i++)
  {
    for (int j = 0; j < 4; j++)
    {
      printf("%5.2f ", p[i][j]);
    }
    printf("\n");
  }
}
           

幾個例子

一維數組

void show(int a[10]) {
  for (int i = 0; i < 5; i++)
  {
    printf("%d\n", a[i]);
  }
}

void main() {
  int num[5] = { 1,2,3,4,5 };
  show(num);
  system("pause");
}
           

二維數組

void show2(int score[2][3]) {
  for (int i = 0; i < 2; i++)
  {
    for (int j = 0; j < 3; j++)
    {
      printf("%d\n", score[i][j]);
    }
    printf("\n");
  }
}

void main() {
  int score[2][3] = { {1,2,3},{3,4,5} };
  show2(score);
  system("pause");
}
           

一維數組名可以作為函數參數,多元數組名也可作函數參數。

用指針變量作形參,以接受實參數組名傳遞來的位址

數組作為函數參數,傳遞的是位址

void show(int *p) {
  for (int i = 0; i < 5; i++)
  {
    //這裡就是一位位移動
    printf("%d\n", *(p + i));//printf("%d\n", p[i]);也是可以的
  }
}

void main() {
  int num[5] = { 1,2,3,4,5 };
  show(num);
  system("pause");
}
           

二維數組

void show(int(*p)[3]) {
  for (int i = 0; i < 2; i++)
  {
    for (int j = 0; j < 3; j++)
    {
      printf("%5d", p[i][j]);
    }
    printf("\n");
  }
}
void main() {
  int score[2][3] = { {1,2,3},{3,4,5} };
  show(score);
  system("pause");
}
           

将數組num的數按反順序輸出

這裡思路,就是數組折半,頭尾互換

//數組沒有副本,這裡會直接修改原資料
void show(int a[],int n) {
  for (int i = 0; i < n/2; i++)
  {
    int tmp = a[i];
    a[i] = a[n - 1 - i];
    a[n - 1 - i] = tmp;
  }
}

void main() {
  int num[5] = { 1,2,3,4,5 };
  show(num, 5);
  for (int i = 0; i < 5; i++)
  {
    printf("%d,", num[i]);
  }
  system("pause");
}
           

數組排序

void sort(int* p, int n) {
  for (int i = 0; i < n-1; i++)
  {
    for (int j = 0; j < n-i-1; j++)
    {
      //主要在這裡,判斷前後兩個數大小,交換
      if (*(p + j) > *(p + j + 1)) {
        int tmp = *(p + j);
        *(p + j) = *(p + j + 1);
        *(p + j + 1) = tmp;
      }
    }
  }
}

void main() {
  int num[6] = {21,22,3,84,15,60 };
  sort(num, 6);
  for (int i = 0; i < 6; i++)
  {
    printf("%d\n", num[i]);
  }
  system("pause");
}
           

函數指針

一個函數在編譯時被配置設定一個入口位址,這個入口位址就稱為函數的指針。

函數名代表函數的入口位址,這一點和數組一樣。我們可以用一個指針變量來存放這個入口位址,然後通過該指針變量調用函數。

函數指針就是指向函數的指針變量。 是以“函數指針”本身首先應是指針變量,隻不過該指針變量指向函數。這正如用指針變量可指向整型變量、字元型、數組一樣,這裡是指向函數。

void (*p)(int data);//函數指針 

void show(int data) {
  data = data + 100;
  printf("%d", data);
}

void main()
{
  p = show;//給函數指針指派
  (*p)(100);
  getchar();
}
           

使用typedef

//typedef來定義一個指針函數
typedef int (*PAdd)(int x, int y);

int add(int x, int y) {
  return x + y;
}

void main() {
  PAdd p = add;
  int sum=p(10, 20);
  printf("%d", sum);
}
           

這裡PAdd等于定義了一個新的類型

p = add可以了解為将函數指針 p 指向 add函數的位址,p(10,20);相當于執行add(10,20);

//typedef來定義一個指針函數
typedef int (*P)(int x, int y);

int add(int x, int y) {
  return x + y;
}

int mul(int x, int y) {
  return x * y;
}

void main() {
  P p = add;
  int sum=p(10, 20);
  p = mul;
  int rate = p(5, 20);
  printf("%d,%d", sum,rate);
}
           

再來一個

#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

void msg() {
  MessageBoxA(0, "你過來呀!", "資訊", 0);
}

void main() {
  void (*p)() = msg;
  p();
}
           

函數傳回值

一個函數可以傳回一個整型值、字元值、實型值等,也可以傳回指針型的資料,即位址

int a = 10;
int b = 20;

//傳回一個指針
int* cal() {
  int c = a + b;
  return &c;//這裡是有風險的
}

void main() {
  printf("%d", *(cal()));
  getchar();
}
           

用指針作為函數傳回值時需要注意的一點是,函數運作結束後會銷毀在它内部定義的所有局部資料,包括局部變量、局部數組和形式參數,函數傳回的指針請盡量不要指向這些資料

int a = 10;
int b = 20;
int c;

//傳回一個指針
int* cal() {
  c = a + b;
  return &c;
}

void main() {
  printf("%d", *(cal()));
  getchar();
}
           

看一下這樣會不會出問題

int a = 10;
int b = 20;

//傳回一個指針
int* cal() {
  int c = a + b;
  return &c;//這裡是有風險的
}

void main() {
  int* p = cal();
  printf("hi\n");
  printf("%d", *p);//這裡發現出問題了。
  getchar();
}
           

在數組中找最大數

int* maxdata(int a[], int n) {
  int* p = NULL;
  int max = a[0];
  p = &a[0];
  for (int i = 0; i < n; i++)
  {
    if (max < a[i]) {
      max = a[i];
      p = &a[i];
    }
  }
  return p;
}

void main() {
  int a[8] = { 1,2,32,112,9,12,98,33 };
  int* p = maxdata(a, 8);
  printf("%d", *p);
}
           

字元串拷貝

#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

void main() {
  char s1[50];
  strcpy(s1, "hello world");
  printf("%s", s1);
}
           

手動一個方法

char* mcopy(char* source, char* dest) {
  while (*source!='\0')
  {
    *dest++ = *source++;
  }
}

void main() {
  char s1[50] = "hello world";
  char s2[50]="";
  mcopy(s1, s2);
  printf("%s\n", s1);
  printf("%s", s2);
}
           

了解一個句柄

12.C語言-指針2
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>


void main() {
  HWND win;//就是指針
  win = FindWindowA("Notepad", "Notepad");//找到一個視窗的句柄,也就是位址
  if (win == NULL)
  {
    printf("沒有找到Notepad");
  }
  else {
    while (1)
    {
      ShowWindow(win, SW_HIDE);//控制隐藏與顯示
      Sleep(1000);
      ShowWindow(win, SW_SHOW);
      Sleep(1000);
    }
    
  }
}
           

Void與空指針

Void* 指針是一種特殊的指針,不指向任何類型的資料,如果需要用此位址指向某類型的資料,應先對位址進行類型轉換。可以在程式中進行顯式的類型轉換,也可以由編譯系統自動進行隐式轉換。無論用哪種轉換 大家必須了解要進行類型轉換

指針變量可以有空值,即該指針變量不指向任何變量,可以這樣表示:

p=NULL
           

用void一定要在取值時轉換類型,其實就是确認長度

void main() {
  int num = 10;
  double db = 10.8;
  int* p1 = #
  void* p2 = p1;//可以接受任務類型位址
  //printf("%d", *p2);//這裡會出錯,void沒有類型
  int* p3 = p2;
  printf("%d\n", *p3);
  printf("%d", *((int*)p2));//轉換類型
}
           
void main() {
  char ch = 'B';
  int num = 99;
  double db = 3.14;
  //非常靈活,什麼都可以指向
  void* p;
  p = &ch;
  printf("%c\n", *((char *)p));
  p = #
  printf("%d\n", *((int*)p));
  p = &db;
  printf("%f\n", *((double*)p));
}
           

空指針

void main() {
  int* p = NULL;
  if (p == NULL) {
    printf("指針為空!");
  }
}
           

memset函數

void memset ( void *s , char ch, unsigned n )

函數功能:将s為首位址的一片連續的n個位元組記憶體單元都指派為ch

#include<stdio.h>
#include<stdlib.h>

void main() {
  char s[50] = "hello world";
  //從首位址開始,将前5個字元指派成A
  memset(s, 'A', 5);
  printf("%s", s);
}
           
#include<stdio.h>
#include<stdlib.h>

void main() {
  int a[10];
  //這裡為什麼是40,因為a是int類型數組,
  //每個元素是4個位元組,是以int[10]實際是40個位元組
  //而memset接受的char隻有1個位元組
  memset(a, 0, 40);
  for (int i = 0; i < 10; i++)
  {
    printf("%d\t", a[i]);
  }
}
           

這裡有個坑,給0沒問題,要是給1就出問題了,因為使用memset函數,對每個位元組指派為1。一個位元組為8位,是以,數組變為

0000 0001 0000 0001 0000 0001 0000 0001