指針引用多元數組
#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);
}
了解一個句柄
#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