1、堆與棧、靜态資料區
【堆棧的動态靜态配置設定】
A,靜态配置設定是指在編譯階段确定大小,由編譯器進行配置設定。
棧的申請就是靜态配置設定的。
B,動态配置設定是指在執行階段确定大小。
堆的申請都是在執行過程中進行的,堆隻能進行動态配置設定。堆在動态配置設定時,要申請連續的記憶體空間,釋放後會産生碎片。
棧也可以使用動态配置設定。
C,堆是使用malloc()、calloc()、realloc()等函數動态配置設定的,而棧使用alloca()函數動态配置設定的記憶體空間,釋放的時候由編譯器自己釋放。
#include<stdio.h>
char *myString()
{
char buffer[6] = {0};
char *s = "Hello World!";
for (int i = 0; i < sizeof(buffer) - 1; i++)
{
buffer[i] = *(s + i);
}
return buffer;
}
int main(int argc, char **argv)
{
printf("%s\n", myString());
return 0;
}
結果:空。buffer存在棧中,随着函數的的結束而消失。應該使用new。
int main()
{
char *p = "hello,world";
return 0;
}
p是局部變量,存在棧中;hello,world存在靜态資料區
【new、malloc】
a、動态配置設定。都是在堆(heap)上進行動态配置設定記憶體。
b、初始化。用malloc不進行初始化,
new 進行初始化,取決于變量定義的位置,在函數體外定義的變量都初始化為0,在函數體内定義的内置類型變量都不進行初始化。
c、delete 會調用對象的destructor,而free 不會調用對象的destructor。
new使用方法
1、new單個對象new在自由空間配置設定記憶體,但其無法為其配置設定的對象命名,因次是無名的,配置設定之後傳回一個指向該對象的指針。int *pi = new int; // pi指向一個動态配置設定的,未初始化的無名對象此new表達式在自由空間構造一個int類型對象,并傳回指向該對象的指針。new是預設初始化的,這意味着内置類型或組合類型的對象的值是無定義的,而類類型對象将用預設構造函數進行初始化。
2、new(多個對象)數組
new配置設定的多個對象也是預設初始化。但可以對數組進行值初始化,方法就是:在大小之後添加一對空括号。int *pia = new int[10]; // 10個未初始化intint *pia2 = new int[10](); // 10個值初始化為0的intdelete使用方法
1、回收用 new 配置設定的單個對象的記憶體空間的時候用 delete,回收用 new[] 配置設定的一組對象的記憶體空間的時候用 delete[]。
2、關于 new[] 和 delete[],其中又分為兩種情況:
(1) 基本資料類型配置設定和回收空間;基本類型的對象沒有析構函數,是以回收基本類型組成的數組空間用 delete 和 delete[] 都是應該可以的;
(2) 自定義類型配置設定和回收空間。但是對于類對象數組,隻能用 delete[],告訴編譯器,釋放的是一塊記憶體,逐一調用析構函數,然後釋放空間。
malloc系列函數
1) malloc 函數: void *malloc(unsigned int size)
在記憶體的動态配置設定區域中配置設定一個長度為size的連續空間。如果配置設定成功,則傳回所配置設定記憶體空間的首位址,否則傳回NULL,申請的記憶體不會進行初始化。
2)calloc 函數: void *calloc(unsigned int num, unsigned int size)
按照所給的資料個數和資料類型所占位元組數,配置設定一個 num * size 連續的空間。
calloc申請記憶體空間後,會自動初始化記憶體空間為 0,但是malloc不會進行初始化,其記憶體空間存儲的是一些随機資料。
3)realloc 函數: void *realloc(void *ptr, unsigned int size)
動态配置設定一個長度為size的記憶體空間,并把記憶體空間的首位址指派給ptr,把ptr記憶體空間調整為size。申請的記憶體空間不會進行初始化。
【靜态區】
static:靜态局部變量一般在聲明處初始化,如果沒有顯式初始化,會被程式自動初始化為0;存放在已初始化區;
2、數組、指針的加減運算
int a[5]={1,2,3,4,5};
int *ptr=(int*)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
輸出:2,5
分析:(1)a:數組名,是一個指針,也就是數組第一個元素的位址。*(a+1)等同于a[1],*(a+1)=2。
(2)&a+1:a是數組名,是一個指針,那麼&a是什麼呢?指針的位址,其指向a[5]數組這個記憶體塊,是以 &a+1 指向數組最後一個元素的 下一個位置,故*(ptr-1)指向數組的最後一個元素。
char *ptr;
char myString[] = "abcdefg";
ptr = myString;
ptr += 5;
代碼執行之後ptr指向的内容是?
fg
int a[3];
a[0] = 0; a[1] = 1; a[2] = 2;
int *p, *q;
p = a;
q = &a[2];
則a[q - p] = 2
#include<stdio.h>
int main(void)
{
int n;
char y[10] = "ntse";
char *x = y;
n = strlen(x);
*x = x[n];
x++;
printf("x=%s\n",x);
printf("y=%s\n",y);
return 0;
}
輸出:x=tse,y=
分析:n = strlen(x),此時n=4,因為x指向y數組,是以x[4]就是y[4]='\0',那麼*x=x[n]就是把x指向的字元串首元素改為'\0',
x++之後x指向第二個字元t,是以第一個輸出x=tse,而y遇到第一個字元就是'\0',是以結束,y輸出為空
本題關鍵是*x = x[n],把最後一個元素指派給首元素。
int main()
{
printf("\n");
int a[5] = {1, 3, 4, 5, 6};
int *p, **k;
p = a;
k = &p;
printf("%d", *(p++));
printf("%d", **k);
return 0;
}
輸出:13
分析:注意*(p++),它與*p++一樣,都是先運算*p,再運算p++,使得p的位址移動一位,是以是3。
【數組、指針大小】
void Func(char str_arg[100])
{
printf("%d\n", sizeof(str_arg));
}
int main(void)
{
char str[] = "Hello";
printf("%d\n", sizeof(str));
printf("%d\n", strlen(str));
char *p = str;
printf("%d\n", sizeof(p));
Func(str);
}
程式輸出:6 5 4 4
分析:str數組名,sizeof(str)為數組的大小,注意這裡不能把str當做指針;這一點也可以從strlen(str)看出;
指針的大小就是4;
函數參數為數組的話,數組會退化為指針,是以Func(str)=4。
在32位系統中:
char arr[] = {4, 3, 9, 9, 2, 0, 1, 5};
char *str = arr;
sizeof(arr) = 8
sizeof(str) = 4
strlen(str) = 5
char *p1= “123”, *p2 = “ABC”, str[50]= "xyz";
strcpy(str+2,strcat(p1,p2));
cout << str;
序的輸出結果是?
出錯
分析:p1,p2指向的是靜态資料區,大小已經配置設定好了,無法使用strcat連接配接,會出錯。
【指針的加減】
unsigned char *p1;
unsigned long *p2;
p1=(unsigned char *)0x801000;
p2=(unsigned long *)0x810000;
請問p1+5= 什麼?
p2+5= 什麼?
程式輸出:801010 810014
分析:p1+5=p1+5*1=p1+5*sizeof(unsigned char)=p1+5*1=0x801000+ox5=0x801005
p2+5=p2+5*1=p2+5*sizeof(unsigned long)=p1+5*4=0x810000+20=0x810000+0x14=0x810014(進制轉換)
#include <stdio. h>
main()
{
int c[6] = {10,20,30,40,50,60}, * p, * s;
p = c;
s = &c[5];
printf("%d\n", s-p );
}
程式運作後的輸出結果是?
答案:5
4、數組指針與二維數組
(一)int a[3][4],下面哪個不能表示 a[1][1]?
A、*(&a[0][0]+5)
B、*(*(a+1)+1)
C、*(&a[1]+1)
D、*(a[1]+1)
答案:C
解析:
在二維數組中a[1]表示的是a[1][0]的位址,數組在記憶體中連續存儲,是以a[1]+1表示的是a[1][1]的位址,是以D可以取得正确的值;
指針操作*(a+1)與a[1]等價,是以B也可以取得正确的值;
二維數組在記憶體中是行優先存儲的,是以A中a[0][0]的位址加5可以取得正确值;
C選項錯誤,應改為*(&a[1][0]+1),否則,則指向a[2][0]。
(二) 要使指針變量p指向2維數組A的第1個元素,正确的指派表達式是()
p=A或p=A[0]
p=A[0]或p=A[0][0]
p=A[0]或p=&A[0][0]
p=A或p=&A[0][0]
答案:第三個選項
分析: A、p = A:它是行指針。在多元數組中,A表示第一維數組,不是第一個元素;
B、p = A[0]:它是指針。在二維數組中,指向的是二維數組的第一個元素;
C、p = &A[0][0]:A[0][0],它是數組元素,表示二維數組的第一個元素,是以可以p = &A[0][0]。
一維數組:數組名表示第一個元素
二維數組:數組名表示第一維數組,行指針;