核心內容:
1、C語言指針的核心知識點
2、處理指針相干問題的萬能措施—-內存分配圖
3、C語言的指針是如何過渡到Java中的援用的
最近1段時間1直在學習C語言的指針,也算是很有心得吧,雖然從網上看了幾篇關于指針的博文,但是感覺都不符合自己的口味,因而決定好好寫1篇關于指針的文章。
C語言指針的核心知識點:
1、指針就是地址,地址就是內存單元的編號,范圍是0到4G⑴,指針的本質就是1個操作受限的非負整數,而指針變量就是寄存內存單元編號(即地址、指針)的變量。
2、凡是動態分配的內存,都是沒著名字的,而是將其地址賦給1個指針變量,用指針變量去代表這個事物。
3、1個指針變量,不管其指向的變量占多少個字節,其本身只占用4個字節的內存空間,由于內存單元的編號是32位。32/8=4
4、字節是存儲數據的基本單元,1個字節占8位,而1個字節的編號占32位。
5、變量分為兩種類型:普通類型變量和指針類型變量,其中普通類型變量用來寄存真實的數據,而指針類型變量用來寄存變量的地址。其中指針類型變量包括(Java中):
①所有類定義的變量:如 Student student = new Student(“zhang” , 25),其中的student
②所有接口定義的變量:如 List list = new ArrayList(),其中的list
③數組的名字:如int a[] = {1,2,3,8,9}中的a。
6、靜態內存是在棧中進行分配的,是由系統自動分配、自動釋放的,靜態內存是程序員沒法控制的;動態內存是在堆中進行分配的,是由程序員手動分配,手動釋放的,凡是動態分配的內存必須通過free的方式才能夠進行釋放,固然這里指的是C語言;在Java當中,動態分配的內存是由內存回收機制來回收的,不用程序員來進行手動回收,保證了程序的安全性,但是在Java當中,由于虛擬機要1直跟蹤每塊內存空間的使用情況,所以常常會從造成CPU的使用率過大。
好的,如果你想學會C語言中的指針,上面的這些內容是你必須要理解的,首先我們先理解1下究竟甚么是指針,在理解究竟甚么是指針之前,我們必須要知道數據在內存中究竟是如何來進行存儲的,先放1張圖:
這里通過1個小例子來講明數據在內存中是如何來進行存儲的:
當我們在Visiual C++6.0軟件對這個程序進行編譯運行的時候,Visiual C++6.0這個軟件首先要求操作系統為我們的變量i分配1塊內存空間,隨后操作系統會在內存中尋覓1塊空閑的區域分配給我們的程序,隨后Visiual C++6.0這個軟件會將變量i和我們的這塊內存空間關聯起來,今后對變量i的操作就是對我們內存空間的操作。具體實現進程以下:
現在我們對內存存儲的這1塊區域進行放大:
操作系統會給我們的變量分配1塊內存空間,但是這塊內存空間究竟在內存中的甚么位置呢?這塊內存空間在內存空間中的編號究竟是多少呢?現在讓我么在程序中輸出1下:
# include <stdio.h>
int main()
{
int i = 10;
printf("編號1的數值是:%#X\n",&i);
return 0;
}
運行結果:
現在我們用圖畫在描寫1下:
在上面這張圖中:(即編號1)就是我們所說的指針,即地址,也就是說:指針實際上就是內存單元的編號,1個編號為32位,每個內存單元都會占有1個內部單元的編號(即地址)記載其在內存條中的位置,因此通過指針我們可以直接對硬件進行操作。
其實,程序歸根結柢就是對內存的操作,我們對1塊內存空間進行操作總共含有兩種方式:
①直接通過變量名的方式對這塊內存空間進行操作。(直接訪問)
②通過獲得內存空間的地址對這塊內存空間進行操作。(間接訪問)
其中,第1種方式是我們常常使用的,但是第2種方式會讓我們有1種直接接觸到硬件的感覺,示例程序:
# include <stdio.h>
int main()
{
int i = 10;
printf("編號1的數值是:%#X\n",&i);
int * p = &i; //指針變量p保存了變量i的地址:18FF44
*p = 100; //以18FF44為地址的那塊內存空間的內容設置為100
printf("變量i的內容是:%d\n",i);//不管是直接訪問還是以地址的間接訪問,本質上都是對同1塊內存空間的訪問
return 0;
}
運行結果:
具體效果:
歸根接地就是1句話:不管是通過變量名i的直接訪問,還是通過地址18FF44的間接訪問,本質上都是對同1塊內存空間的訪問。
處理指針相干問題的萬能措施—-內存分配圖
很多人在處理指針這塊的程序的時候,有的時候總是會感覺到很迷糊,但是就我個人而言,對指針相干的知識,總是習慣于去畫內存分配圖去解決問題,而且效果還是非常好的,下面我們就用1個典型的程序:交換內容的程序來講明問題。
要求:輸入a和b兩個整數,依照先大后小的順序輸出a和b。
實例程序1:
# include <stdio.h>
void swap(int ,int );
int main()
{
int a,b;
printf("請從鍵盤上輸入a和b兩個數值:\n");
scanf("%d %d",&a,&b);
if (a < b)
{
swap(a,b);
}
printf("max=%d \t min=%d \n",a,b);
return 0;
}
void swap(int p,int q)
{
int tmp; //交換p和q的內容
tmp = p;
p = q;
q = tmp;
}
運行結果:
很明顯,從運行結果上來看,并沒有到達我們的預期效果,下面我們用內存分配圖來查找1下緣由:
所以上面程序的解法是毛病的。
實例程序2:
# include <stdio.h>
void swap(int *,int *);
int main()
{
int a,b;
printf("請從鍵盤上輸入a和b兩個數值:\n");
scanf("%d %d",&a,&b);
if (a < b)
{
swap(&a,&b);
}
printf("max=%d \t min=%d \n",a,b);
return 0;
}
void swap(int *p,int *q)
{
int tmp;
tmp = *p;
*p = *q;
*q = tmp;
}
運行結果:
內存分配圖:
通過上面的圖解我們可以發現,指針變量p和q分別定位到了變量a和變量b的內存空間,間接的交換了a和b內存空間的內容。
C語言的指針是如何過渡到Java中的援用的
在談到這個問題的時候,我認為應當從兩個方面進行說起:動態內存分配和如何傳遞發送內容。
動態內存份分配的問題:
實例程序1:
# include <stdio.h>
# include <malloc.h>
# include <string.h>
struct Student
{
char name[100];
int age;
float score;
};
int main()
{
Student * student = (Student *)malloc(sizeof(Student));
strcpy(student->name,"zhangming");
student->age = 25;
student->score = 88.8f;
printf("name is %s\n",student->name); //student->age在編譯底層會變成(*student).name
printf("age is %d\n",student->age);
printf("score is %f\n",student->score);
return 0;
}
運行結果:
內存實例圖示:
對上面的這個程序,Java語言是這么封裝的:
class Student
{
String name;
int age;
float score;
}
public class App1
{
public static void main(String[] args)
{
//Student * student = (Student *)malloc(sizeof(Student));
Student student = new Student(); //new相當于C語言中的malloc
student.name = "zhangsan";
student.age = 25;
student.score = 88.8f;
System.out.println("name is:"+student.name);
System.out.println("age is:"+student.age);
System.out.println("score is:"+student.score);
}
}
下面我們通過函數傳遞數據:傳遞指針變量(本質傳遞的是地址)
# include <stdio.h>
# include <malloc.h>
# include <string.h>
struct Student
{
char name[100];
int age;
float score;
};
void changeData(Student * stu)
{
strcpy(stu->name,"lisi");
stu->age = 24;
stu->score = 98.8f;
}
int main()
{
Student * student = (Student *)malloc(sizeof(Student));
strcpy(student->name,"zhangming");
student->age = 25;
student->score = 88.8f;
printf("name is %s\n",student->name); //student->age在編譯底層會變成(*student).name
printf("age is %d\n",student->age);
printf("score is %f\n",student->score);
changeData(student);//傳遞的是地址,速度快并且節省內存空間!
printf("name is %s\n",student->name); //student->age在編譯底層會變成(*student).name
printf("age is %d\n",student->age);
printf("score is %f\n",student->score);
return 0;
}
運行結果:
Java封裝的效果:
class Student
{
String name;
int age;
float score;
}
public class App1
{
public static void main(String[] args)
{
//Student * student = (Student *)malloc(sizeof(Student));
Student student = new Student(); //new相當于C語言中的malloc
student.name = "zhangsan";
student.age = 25;
student.score = 88.8f;
System.out.println("name is:"+student.name);
System.out.println("age is:"+student.age);
System.out.println("score is:"+student.score);
changeData(student); //student本質上是1個指針變量
System.out.println("name is:"+student.name);
System.out.println("age is:"+student.age);
System.out.println("score is:"+student.score);
}
public static void changeData(Student stu) //stu指向同1塊內存空間
{
stu.name = "lisi";
stu.age = 24;
stu.score = 98.8f;
}
}
運行結果:
name is:zhangsan
age is:25
score is:88.8
name is:lisi
age is:24
score is:98.8
總結:在Java當中,雖然已沒有了指針,但是底層編譯運行進程中本質上就是指針,Java中的援用本質上就是C語言中的指針變量,不管是C語言還是Java語言,都有1個共同的特點:凡是動態分配的內存都是沒著名字的,而是用1個指針變量保存這塊內存空間的地址,用這個指針變量去代表這塊內存空間。
OK,博文如果有問題,歡迎大家留言指正!