1.指針的算術運算
(1)指針之間不允許相加,但允許相減
指針相減表示兩個指針之間間隔的單元格數(1.先計算出字節數 2.再除以權重)
(2)指針運算需要調整
p+數字(n) 加n單元格的權重 權重爲指針變量去掉一個*,求sizeof(),乘n
數字之間不需要調整,直接加或減
#include <stdio.h>
#include <stdlib.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9};
int *p = arr; //指針-指針
int *q = &arr[8];
printf("%d\n",p-q);//-8
printf("%d\n",q-p);//8
printf("%d\n",(short *)q-(short *)p);//16
printf("%d\n",(double *)q-(double *)p);//4
printf("%d\n",(unsigned long)q-(unsigned long)p);//32
int *p1 = (int *)2000;//指針+-數字
printf("%d\n",p1+2);//2008
printf("%d\n",(char *)p1+2);//2002
printf("%d\n",(long long)p1+2);//2002
printf("%d\n",(double **p1+2);//2008
}
2.數組和指針的替換
int arr[10];
int *p = arr;
arr[i] = *(arr+i);
p[i] = *(p+i);
3.指針和數組的其他知識
(1)數組名代表整個數組長度的兩種情況
int arr[10] = {0,1,2,3,4,5,6,7,8,9};
sizeof(arr) = 40;
cout<<&arr<<endl;//1000
cout<<&arr+1<<endl;//1040
(2)類型
int arr[10]; int *p = arr;
int brr[3][4]; int (*q)[4] = brr;//二維數組的數組名是指向一位數組的指針
brr[0]是int*類型
brr[0]+1是int*類型(+數字,對類型無影響)
brr[2][3]是int類型
(3)二位數組是否越界
int brr[3][4] = {{1,2,3},{4,5,6},{7}};
printf("%d\n",brr[0][6]);//6 二維數組是線性存儲的,可以越界訪問
(4)字符串的定義正確的是?
char str1[5] = {'a','b','c'};//ok
char str2[5] = {"abc"};//ok
char str3[5] = "abc";//ok
char str4[] = "hello"; //ok
char str5[5] = "hello";//error,越界
(5)字符數組的大小
sizeof—求內存的字節數,所有的字符都要放進去
strlen—字符串的有效長度,碰到’\0’就結束
#include <stdio.h>
int main()
{
char str1[100] = "abcde";
char str2[100] = "abcd\0ef\n";
char *str3 = "abcde";
char *str4 = "abcd\0ef\n";
char str5[] = "abcde";
char str6[] = "abcd\0ef\n";
printf("%d,%d\n",sizeof(str1),strlen(str1));//100,5
printf("%d,%d\n",sizeof(str2),strlen(str2));//100,4
printf("%d,%d\n",sizeof(str3),strlen(str3));//4,5
printf("%d,%d\n",sizeof(str4),strlen(str4));//4,4
printf("%d,%d\n",sizeof(str5),strlen(str5));//6,5
printf("%d,%d\n",sizeof(str6,strlen(str6);//9,4
return 0;
}
(6)字符數組和字符串常量的區別
int main()
{
char *str1 = "abcde";//1
char str2[] = "abcde";//2
str1[0] = 'x';//3 編譯沒問題,運行崩潰
str2[0] = 'x';//4
return 0;
}
str1是字符常量,在全局靜態變量區(.rodata段),不能修改其值
str2是字符數組,在棧上,自己的內存,可以隨便修改
改錯題可能會考,需要在定義時顯示的加上const,這樣編譯就不會通過
const const char *str1 = “abcde”;
(7)下列各變量的含義
int *a;//整型指針
int *b();//函數,無參數,返回值是int *
int c[4];//整型數組
int *d[4];//指針數組,每個數組的元素是一個int類型的指針
int (*e)[4];//數組指針,該指針指向一個含有4個整型元素的數組
int (*f)();//函數指針,該指針指向一個函數,函數無參數,返回值是int類型
4.交換函數
#include <stdio.h>
void Swap1(int *p1, int *p2)
{
int *tmp = p1;
p1 = p2;
p2 = tmp;
}
void Swap2(int *p1, int *p2)
{
int *tmp;//野指針
*tmp = *p1;
*p1 = *p2;
*p2 = *tmp;
}
void Swap3(int *p1, int *p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
int main()
{
int a = 10;
int b = 20;
printf("a=%d,b=%d\n",a,b);
Swap1(&a, &b);
printf("swap1:a=%d,b=%d\n",a,b);
Swap2(&a, &b);
printf("swap2:a=%d,b=%d\n",a,b);
Swap3(&a, &b);
printf("swap3:a=%d,b=%d\n",a,b);
return 0;
}
子函數和父函數之間要建立聯繫,必須傳指針並解引用
5.返回數組/指針
#include <stdio.h>
char *Fun1()
{
char arr[] = "hello world";
return arr;
}
int main()
{
printf("%s\n",Fun1());///返回局部數組,亂碼
}`
arr是局部變量,出Fun1函數後,函數棧幀回退,arr的地址可能已經被重新分配給別的函數使用。不能返回局部變量!!!
6.結構體和聯合體
struct A
{
char a;//1+1
short b;//2
int c;//4
};//8
struct B
{
char a;//1+3
int b;//4
short c;//2
};//10+2
struct C//位段
{
int a:10;//a佔10位
int b:2;//a佔2位
};//4,必須是int的倍數
struct D
{
char a;//1
struct DD//有類型有變量,以單個最大的數據類型對齊
{
char b;//1+3
int c;//4
}d;//8
};//9+3
struct E
{
short a;//2
struct EE//有類型沒變量,不佔內存
{
char b;
int c;
};//不佔內存
int d;//4
};//6+2
struct F
{
int a;//4
struct//沒類型沒變量,生成一個透明的變量,a/b/c/d同級
{
char b;//1+3
float c;//4
};
char d;//1+3
};//16
struct G
{
char a;//1
struct//只有變量沒有類型(與有變量有類型)相同
{
char b;//1+3
int c;//4
}d;//8
};//9+3
union H//共用體
{
char a;
short b;
int c;
};//4
7.可變參數編程 3個宏
需要引入頭文件#include<stdarg.h>
va_list list;//相當於char* list;
va_start(list, num);//找到...開頭
va_arg(list,int);//從…取數據
va_end(list);//list==NULL,關閉
編程題:編寫一個名叫max_list的函數,它用於檢查任意數目的整型參數並返回它們中的做大值,參數列表必須以一個負數結尾,提示列表的結束。
#include <iostream>
#include <stdarg.h>
using namespace std;
int Max_list(int a,...)//1,4,9,-1
{
int max = a;
int cur = a;
va_list list;//char *list;
va_start(list,a);//找到...開頭
while(cur >= 0)
{
cur = va_arg(list,int);//從...取數據
if(max < cur)
{
max = cur;
}
}
va_end(list);//list = NULL;
return max;
}
int main()
{
printf("%d\n",Max_list(1,5,9,0,2,5,-1));
return 0;
}
8.malloc常見錯誤
malloc一般都是內存的問題(程序崩潰/內存泄露)
面試題:C++是兼容C的,C已經有了malloc/free,C++爲什麼還要有new/delete?
答:malloc/free是C語言的標準庫函數,new/delete是C++的運算符
對於非內置數據類型的對象來說,使用malloc/free無法滿足動態創建對象的要求。對象創建的時候要自動調用構造函數,對象消亡的時候要自動調用析構函數。malloc/free是庫函數,不在編譯器權限的控制範圍內,不能把調用構造函數和析構函數的任務強加給malloc/free。因此,C++需要一個能完成動態分配並初始化內存的運算符new,一個可以清理並釋放內存的運算符delete。