1.排序
形參中的數(shù)組与柑,編譯器會把他當(dāng)作指針處理
形參寫在函數(shù)上庇谆,和寫在函數(shù)內(nèi)是一樣的忌锯,只不過是
寫在函數(shù)上具有對外的屬性
2.關(guān)于數(shù)組地址
看下面函數(shù)的運行結(jié)果,你會發(fā)現(xiàn)漩氨,b+1和&b+1的區(qū)別西壮,b表示的是數(shù)組元素首地址,所以b+1就是將從首元素向后移動一個元素后得到的第二個元素的地址叫惊,但是&b+1的結(jié)果優(yōu)點出乎意料款青,它相對于首元素地址向后移動了40個位置,而40剛好是數(shù)組b的長度霍狰,怎么解釋呢抡草,其實就是&b表示的是整個數(shù)組的地址,把整個數(shù)組當(dāng)作一個整體蔗坯,那么加一就是移動這樣一個整體后的地址了
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void main() {
int b[10];
printf("b:%d,b+1:%d,&b+1:%d", b, b + 1, &b + 1);
system("pause");
}
打印結(jié)果:
b:19922588,b+1:19922592,&b+1:19922628請按任意鍵繼續(xù). . .
1)數(shù)組首元素的地址和數(shù)組地址是兩個不同的概念
2)數(shù)組名代表數(shù)組首元素地址康震,他是個常量
解釋如下:變量本質(zhì)是內(nèi)存空間的別名,而數(shù)組在定義時就會分配內(nèi)存步悠,內(nèi)存就固定了签杈,所以數(shù)組名起名以后就不能更改了
3)數(shù)組首元素的地址和數(shù)組值相等
C語言規(guī)定:
int a[10]
&a表示整個數(shù)組的地址瘫镇,a表示數(shù)組首元素的地址鼎兽,區(qū)別體現(xiàn)在地址+1的結(jié)果
如何定義一個數(shù)組數(shù)據(jù)類型
int a;//定義了一個int類型a
typedef int (MyArrayType)[5];//定義一個數(shù)組數(shù)據(jù)類型MyArrayType,
MyArrayType myArray; //相當(dāng)于int myArray[5]
myArray[0] = 0;
...
myArray[4]=4;
定義數(shù)組指針的第一種方法
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void main() {
char *MyArray[] = {"1111","2222","3333"};
//數(shù)組指針,一個指針铣除,指向了數(shù)組
//定義了一個數(shù)組數(shù)據(jù)類型
typedef int(MyArrayType)[5];
int i = 0;
//用類型定義變量谚咬,相當(dāng)于int myArray[5]
MyArrayType myArray;
//定義一個指針變量,這個變量指向數(shù)組
MyArrayType *pArray;
//定義一個數(shù)組尚粘,相當(dāng)于一級指針
int myArray2[5];
//數(shù)組指針指向這個數(shù)組择卦,相當(dāng)于二級指針
pArray = &myArray2;
for (i = 0; i < 5; i++) {
(*pArray)[i] = i + 1;
}
for (i = 0; i < 5; i++) {
printf("%d", (*pArray)[i]);
}
system("pause");
}
定義數(shù)組指針的第二種方法
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void main() {
//定義聲明一個數(shù)組指針類型
typedef int(*PArrayType)[5];
//告訴編譯器給我分配一個指針變量
PArrayType pArray;
//定義一個數(shù)組,相當(dāng)于一級指針
int myArray2[5];
//數(shù)組指針指向這個數(shù)組郎嫁,相當(dāng)于二級指針
pArray = &myArray2;
int i = 0;
for (i = 0; i < 5; i++) {
(*pArray)[i] = i + 1;
}
for (i = 0; i < 5; i++) {
printf("%d", (*pArray)[i]);
}
system("pause");
}
定義數(shù)組指針的第三種方法
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void main() {
//直接定義一個指向數(shù)組的數(shù)組指針變量
int(*PArrayType)[5];
//定義一個數(shù)組秉继,相當(dāng)于一級指針
int myArray2[5];
//數(shù)組指針指向這個數(shù)組,相當(dāng)于二級指針
PArrayType = &myArray2;
int i = 0;
for (i = 0; i < 5; i++) {
(*PArrayType)[i] = i + 1;
}
for (i = 0; i < 5; i++) {
printf("%d", (*PArrayType)[i]);
}
system("pause");
}
3.內(nèi)存四區(qū)的建立流程
4.寫一段程序證明棧的生長方向(開口向上還是開口向下)
在棧內(nèi)存中定義兩個變量ab一個數(shù)組buf泽铛,比較他們的地址尚辑。如圖所示,如果棧的開口向上盔腔,那么先入棧的變量地址會小于后入棧的變量地址杠茬,如果開口向下則反之月褥,所以可以根據(jù)這個特性來判斷,我們打印了ab的地址瓢喉,結(jié)果是a地址大于b宁赤,那么可以確定當(dāng)前環(huán)境下,棧開口是向下的栓票,可以默認棧的開口是向下的决左,這種情況比較多。
同時可以看到我們定義了一個數(shù)組逗载,可以看到哆窿,雖然棧開口向下,但是數(shù)組中元素的存儲方式并沒有像棧中元素ab一樣厉斟,你在棧開口向上的情況下試一下會發(fā)現(xiàn)挚躯,棧的開口不影響數(shù)組元素的存儲形式,數(shù)組存儲永遠是圖中所示的樣子
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void main() {
int a;
int b;
printf("&a:%d,&b:%d\n", &a, &b);
char buf[2] = {'a','b'};
printf("&buf[0]:%d,&buf[1]:%d\n", &buf[0], &buf[1]);
system("pause");
}
打印結(jié)果
&a:8387696,&b:8387684
&buf[0]:8387672,&buf[1]:8387673
請按任意鍵繼續(xù). . .
5.strcpy函數(shù)的5中推演方式
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/*
移動from和to指針擦秽,當(dāng)from指針到達末尾的時候跳出
*/
void copy1(char *from, char *to) {
for (; *from != '\0'; from++, to++) {
*to = *from;
}
//在字符串的末尾加上\0,因為拷貝的時候跳過了\0
*to = '\0';
return;
}
/*
把自增運算放在了循環(huán)中码荔,++優(yōu)先級大于*
但是因為++是放在后邊的,所以整體執(zhí)行順序還是先
將*from賦值給*to,然后from和to做自增運算
*/
void copy2(char *from, char *to) {
for (; *from != '\0';) {
*to++ = *from++;
}
*to = '\0';
return;
}
/*
這種寫法可以減少手動在末尾添加0的操作感挥,
(*to = *from) != '\0'這行代碼做了兩部操作
第一先賦值缩搅,第二判斷是否是0,所以當(dāng)?shù)竭_末尾
得的時候触幼,0也被拷貝了
*/
void copy3(char *from, char *to) {
while ((*to = *from) != '\0') {
from++;
to++;
}
}
/*
這個操作更加簡化硼瓣,所以操作寫在了判斷條件中
*/
void copy4(char *from, char *to) {
while ((*to++ = *from++) != '\0') {
}
}
/*
最簡版
*/
void copy5(char *from, char *to) {
while (*to++ = *from++) {
}
}
void main() {
char *from = "hello world";
char to[100];
copy5(from, to);
//C語言打印數(shù)據(jù)會將數(shù)組元素打印出來
printf("to:%s\n", to);
system("pause");
}
6.字符串反轉(zhuǎn)的兩種方式
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
//兩頭堵模型實現(xiàn)字符串反轉(zhuǎn)
void inverse1(char *str) {
int length;
char *start;
char *end;
length = strlen(str);
start = str;
end = str + length - 1;
while (start < end) {
char c = *start;
*start = *end;
*end = c;
++start;
--end;
}
}
/*
遞歸調(diào)用實現(xiàn)字符串反轉(zhuǎn),這一點利用了棧的結(jié)構(gòu)特點,先入后出
不斷的將字符串中每一個字符入棧置谦,最后打印每一個字符堂鲤,由后往前
*/
void inverse2(char *str) {
if (str == NULL) return;
//到達字符串末尾,結(jié)束遞歸
if (*str == '\0') return;
inverse2(str + 1);
printf("%c", *str);
}
/*
將反轉(zhuǎn)后的字符串保存到全局變量中
*/
//全局變量被修改媒峡,多線程操作中會涉及到線程安全的問題
char buf[100];
void inverse3(char *str) {
if (str == NULL) return;
//到達字符串末尾瘟栖,結(jié)束遞歸
if (*str == '\0') return;
inverse3(str + 1);
strncat(buf, str,1);
}
void main() {
char a[] = "abcdefg";
//inverse1(a);
//printf("%s\n", a);
//inverse2(a);
memset(buf, 0, sizeof(buf));
inverse3(a);
printf("buf = %s\n", buf);
system("pause");
}
7.const深入理解
int main(){
const int a;
int const b;
const char *c;
char * const d;
const char * const e;
}
1.const修飾常量,前兩種情況是相同的谅阿,表示常量ab都不能被修改
2.const修飾指針半哟,第三種是一個指向常整型的指針,他所指向的內(nèi)存數(shù)據(jù)不能被修改签餐,但是他本身可以被修改寓涨,也就是所,可以修改他指向的地址
3.const修飾指針氯檐,第四種是一個常量指針戒良,指針變量不能被修改,但是他指向的內(nèi)存空間可以被修改男摧,不能改變指向蔬墩,但是值可變
4.const修飾指針译打,第五種是一個指向常整型的常量指針,指針和他指向的內(nèi)存空間都不能被修改
8.二級指針做函數(shù)參數(shù)的作用
通過二級指針做參數(shù)的好處是拇颅,可以用于修改原一級指針所指向的內(nèi)存奏司,同時也可以修改原一級指針的指向。那么直接用一級指針做參數(shù)進行傳遞就做不到這兩點了嗎樟插,答案是韵洋,可以做到其中以點,就是操作原一級指針指向的內(nèi)存黄锤,但是無法對原一級指針進行操作
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/*
二級指針做函數(shù)參數(shù)搪缨,用于修改傳入一級指針的指向
*/
int getMem(char **a1, int *myLen1, char ** a2, int *myLen2) {
char *temp1 = NULL;
char *temp2 = NULL;
temp1 = (char *)malloc(100);
if (temp1 == NULL) {
return -1;
}
strcpy(temp1, "hello");
//讓傳入的二級指針指向的指針指向temp指向的內(nèi)存空間
//這行代碼的意思:*a1表示p1,讓p1指向了temp1指向的空間
*a1 = temp1;
temp2 = (char *)malloc(100);
if (temp2 == NULL) {
return -1;
}
strcpy(temp2, " world");
*a2 = temp2;
}
/*
通過二級指針釋放一級指針指向的內(nèi)存
*/
void freeMem(char** temp1, char **temp2) {
if (temp1 == NULL || temp2 == NULL)
{
return;
}
free(*temp1);
*temp1 = NULL;
free(*temp2);
*temp2 = NULL;
}
/*
如果傳入一級指針釋放內(nèi)存會怎樣?
*/
void freeMem(char* temp1, char *temp2) {
if (temp1 == NULL || temp2 == NULL)
{
return;
}
free(temp1);
//這一步只是將局部變量temp1設(shè)置為null,所以并不影響main函數(shù)
//中p1這個變量鸵熟,所以傳遞一級指針副编,無法操作原一級指針變量
temp1 = NULL;
free(temp2);
//這一步只是將局部變量temp2設(shè)置為null,所以并不影響main函數(shù)
//中p2這個變量,所以傳遞一級指針流强,無法操作原一級指針變量
temp2 = NULL;
}
void main() {
char *p1 = NULL;
int len1 = 0;
char *p2 = NULL;
int len2 = 0;
int ret;
ret = getMem(&p1, &len1, &p2, &len2);
printf("%s\n", p1);
printf("%s\n", p2);
freeMem(&p1, &p2);
system("pause");
}
9.二級指針做輸入痹届,指向指針數(shù)組
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void printArr(char** temp, int num) {
int i = 0;
for (; i < num; i++) {
//注意,這里*(temp) = *(temp+0) ,二級指針指向
//指針數(shù)組打月,*(temp+i)表示的是原數(shù)組arr中的第i
//個元素的地址队腐,而我們知道,C語言直接打印數(shù)組
//元素的地址奏篙,就會將數(shù)組元素打印出來
printf(" *(temp + %d) = %s\n", i, *(temp + i));
}
}
void bubbleSort(char **temp, int num) {
int i = 0, j = 0;
for (int i = 0; i<num - 1; i++) {//外層循環(huán)控制排序趟數(shù)
for (int j = 0; j<num - 1 - i; j++) {//內(nèi)層循環(huán)控制每一趟排序多少次
if (strcmp(*(temp + j),*(temp + j + 1))>0)
{
char *smallest = *(temp + j);
*(temp + j) = *(temp + j + 1);
*(temp + j + 1) = smallest;
}
}
}
}
void main() {
//這是一個指針數(shù)組柴淘,存放的是是每個元素的地址
char *arr[] = {"aaaaa","ccccc","ddddd","bbbbb"};
int num = sizeof(arr) / sizeof(arr[0]);
printf("數(shù)組的長度是:%d\n", num);
printf("排序之前\n");
printArr(arr, num);
bubbleSort(arr, num);
printf("排序之后\n");
printArr(arr, num);
system("pause");
}
順便復(fù)習(xí)一下冒泡排序
原理:依次比較相鄰的兩個數(shù),將小數(shù)放在前面秘通,大數(shù)放在后面为严。即在第一趟:首先比較第1個和第2個數(shù),將小數(shù)放前充易,大數(shù)放后梗脾。然后比較第2個數(shù)和第3個數(shù)荸型,將小數(shù)放前盹靴,大數(shù)放后,如此繼續(xù)瑞妇,直至比較最后兩個數(shù)稿静,將小數(shù)放前,大數(shù)放后辕狰。重復(fù)第一趟步驟改备,直至全部排序完成。
舉例說明:要排序數(shù)組:int[] arr={6,3,8,2,9,1};
第一趟排序:
第一次排序:6和3比較蔓倍,6大于3悬钳,交換位置: 3 6 8 2 9 1
第二次排序:6和8比較盐捷,6小于8,不交換位置:3 6 8 2 9 1
第三次排序:8和2比較默勾,8大于2碉渡,交換位置: 3 6 2 8 9 1
第四次排序:8和9比較,8小于9母剥,不交換位置:3 6 2 8 9 1
第五次排序:9和1比較:9大于1滞诺,交換位置: 3 6 2 8 1 9
第一趟總共進行了5次比較, 排序結(jié)果: 3 6 2 8 1 9
第二趟排序:
第一次排序:3和6比較环疼,3小于6习霹,不交換位置:3 6 2 8 1 9
第二次排序:6和2比較,6大于2炫隶,交換位置: 3 2 6 8 1 9
第三次排序:6和8比較淋叶,6大于8,不交換位置:3 2 6 8 1 9
第四次排序:8和1比較伪阶,8大于1爸吮,交換位置: 3 2 6 1 8 9
第二趟總共進行了4次比較, 排序結(jié)果: 3 2 6 1 8 9
第三趟排序:
第一次排序:3和2比較望门,3大于2形娇,交換位置: 2 3 6 1 8 9
第二次排序:3和6比較,3小于6筹误,不交換位置:2 3 6 1 8 9
第三次排序:6和1比較桐早,6大于1,交換位置: 2 3 1 6 8 9
第二趟總共進行了3次比較厨剪, 排序結(jié)果: 2 3 1 6 8 9
第四趟排序:
第一次排序:2和3比較哄酝,2小于3,不交換位置:2 3 1 6 8 9
第二次排序:3和1比較祷膳,3大于1陶衅,交換位置: 2 1 3 6 8 9
第二趟總共進行了2次比較, 排序結(jié)果: 2 1 3 6 8 9
第五趟排序:
第一次排序:2和1比較直晨,2大于1搀军,交換位置: 1 2 3 6 8 9
第二趟總共進行了1次比較, 排序結(jié)果: 1 2 3 6 8 9
最終結(jié)果:1 2 3 6 8 9
由此可見:N個數(shù)字要排序完成勇皇,總共進行N-1趟排序罩句,每i趟的排序次數(shù)為(N-i)次,用雙重循環(huán)語句敛摘,外層控制循環(huán)多少趟门烂,內(nèi)層控制每一趟的循環(huán)次數(shù)
10.二級指針做輸入,第二種形式
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void main() {
int i = 0;
char **p2 = NULL;
int num = 5;
//在堆空間中開辟內(nèi)存空間,大小是sizeof(char*)*num屯远,
//用于存儲5個char*類型的指針變量
p2 = (char **)malloc(sizeof(char*)*num);
//開辟空間之后給每個元素賦值
for (i = 0; i < num; i++) {
//給每個char*類型的指針變量開辟指向的內(nèi)存空間蔓姚,這個空間
//用于存放char類型的數(shù)據(jù),最大可存100個char
*(p2+i) = (char*)malloc(sizeof(char) * 100);
//賦值
sprintf(*(p2 + i), "存入我的數(shù)據(jù)%d,", i + 1);
}
for (i = 0; i < num; i++) {
printf("%s\n", *(p2 + i));
}
//釋放
for (i = 0; i < num; i++) {
if (*(p2 + i) != NULL) {
free(*(p2 + i));
*(p2 + i) = NULL;
}
}
if (p2 != NULL)
{
free(p2);
p2 = NULL;
}
system("pause");
}
void main2() {
int i = 0;
char **p2 = NULL;
int num = 5;
//在堆空間中開辟內(nèi)存空間慨丐,大小是sizeof(char*)*num赂乐,
//用于存儲5個char*類型的指針變量
p2 = (char **)malloc(sizeof(char*)*num);
//開辟空間之后給每個元素賦值
for (i = 0; i < num; i++) {
//給每個char*類型的指針變量開辟指向的內(nèi)存空間,這個空間
//用于存放char類型的數(shù)據(jù)咖气,最大可存100個char
p2[i] = (char*)malloc(sizeof(char) * 100);
//賦值
sprintf(p2[i], "存入我的數(shù)據(jù)%d,", i + 1);
}
for (i = 0; i < num; i++) {
printf("%s\n", p2[i]);
}
//釋放
for (i = 0; i < num; i++) {
if(p2[i] != NULL) {
free(p2[i]);
p2[i] = NULL;
}
}
if (p2 != NULL)
{
free(p2);
p2 = NULL;
}
system("pause");
}
11.二級指針操作字符串練習(xí)
切割字符串并存儲在堆內(nèi)存中挨措,然后打印切割結(jié)果
char *p1 = "abcdef,acccd,eeee,aaaa,e3eeeee,sssss,ssccccccc,";
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int splitString(const char *buf1, char c, char** myp, int *count) {
char *p = NULL, *ptmp = NULL;
int tmpcount = 0;
//兩個指針都指向了字符串指針
p = buf1;
ptmp = buf1;
do {
//從p中找char c
p = strchr(p, c);
if (p != NULL) {
//大于0說明指針已經(jīng)有移動位置,新的字符串和舊的不是同一個崩溪,
//如果字符串第一個字符就找到了符合條件的浅役,那么p-pmt = 0
if (p - ptmp > 0) {
//找到一個逗號后,將逗號之前的字符串拷貝到二級指針指向的空間中
strncpy(*(myp + tmpcount), ptmp, p - ptmp);
//在截出來的字符串后邊添加字符串結(jié)束符\0
*(*(myp + tmpcount) + (p - ptmp)) = '\0';
tmpcount++;
ptmp = p = p + 1;
/*strncpy(myp[tmpcount], ptmp, p - ptmp);
myp[tmpcount][p - ptmp] = '\0';
tmpcount++;
ptmp = p = p + 1;*/
}
}
else {
break;
}
} while (*p != '\0');
*count = tmpcount;
return *count;
}
void main() {
int ret = 0, i = 0;
char *p1 = "abcdef,acccd,eeee,aaaa,e3eeeee,sssss,ssccccccc,";
char cTemp = ',';
int count;
//開辟空間
char **p = NULL;
p = (char **)malloc(10 * sizeof(char *));
if (p == NULL) {
return;
}
for (i = 0; i < 10; i++) {
*(p + i) = (char *)malloc(sizeof(char)*30);
//p[i] = (char *)malloc(sizeof(char) * 30);
}
ret = splitString(p1, cTemp, p, &count);
printf("得到了%d個元素\n", count);
if (ret == 0)
{
printf("error\n");
}
for (i = 0; i < count; i++) {
printf("%s\n", *(p + i));
}
//回收內(nèi)存
for (i = 0; i < 10; i++) {
if (*(p + i) != NULL) {
free(*(p + i));
*(p + i) = NULL;
}
}
if (p != NULL)
{
free(p);
p = NULL;
}
//釋放
/*for (i = 0; i < num; i++) {
if (p2[i] != NULL) {
free(p2[i]);
p2[i] = NULL;
}
}
if (p2 != NULL)
{
free(p2);
p2 = NULL;
}*/
system("pause");
}
12.定義數(shù)組指針的三種方式
1)通過數(shù)組類型定義數(shù)組指針
typedef int(ArrayType)[5];
ArrarType *pointer;
- 聲明一個數(shù)組指針類型
typedef int (*MyPointer)[5];
MyPointer myPoint; - 直接定義
int(*pointer)[n];
ponter為數(shù)組指針變量名
type (int)為指向的數(shù)組的類型
n 為指向的數(shù)組的大小
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void main() {
//直接定義一個指向數(shù)組的數(shù)組指針變量
int(*PArrayType)[5];
//定義一個數(shù)組伶唯,相當(dāng)于一級指針
int myArray2[5];
//數(shù)組指針指向這個數(shù)組觉既,相當(dāng)于二級指針
PArrayType = &myArray2;
int i = 0;
for (i = 0; i < 5; i++) {
(*PArrayType)[i] = i + 1;
}
for (i = 0; i < 5; i++) {
printf("%d", (*PArrayType)[i]);
}
system("pause");
}
void main2() {
char *MyArray[] = {"1111","2222","3333"};
//數(shù)組指針,一個指針乳幸,指向了數(shù)組
//定義了一個數(shù)組數(shù)據(jù)類型
typedef int(MyArrayType)[5];
int i = 0;
//用類型定義變量瞪讼,相當(dāng)于int myArray[5]
MyArrayType myArray;
//定義一個指針變量,這個變量指向數(shù)組
MyArrayType *pArray;
//定義一個數(shù)組粹断,相當(dāng)于一級指針
int myArray2[5];
//數(shù)組指針指向這個數(shù)組符欠,相當(dāng)于二級指針
pArray = &myArray2;
for (i = 0; i < 5; i++) {
(*pArray)[i] = i + 1;
}
for (i = 0; i < 5; i++) {
printf("%d", (*pArray)[i]);
}
system("pause");
}