C語言重要知識點回顧

太久沒有看C語言相關知識了,開始要整理回顧一些重點知識點啦,因爲各大公司筆試還是有許多C語言相關的題,做個複習。

const 關鍵字與指針修飾使用

普通指針使用:

//普通指針使用,我們通過 i 或者 p 指針都能改變變量值
void test1()
{
	int i = 1;
	int * p = &i;

	printf("p=%d\n",*p);
	i = 2;
	printf("p=%d\n",*p);
	(*p)++;
	printf("p=%d\n",*p);
	printf("i=%d\n",i);
}

輸出結果:


這個結果是我們好理解的。

接着 const int *p 問題

// const int *p 表示p 所指的對象是隻讀不可以改變的,但p 指針可以指向其他地址
void test2()
{
	int i = 1;
	int j = 100;
	const int * p = &i;

	printf("p=%d\n",*p);

	i = 2;

	printf("p=%d\n",*p);

	p = &j;
	printf("p=%d\n",*p);

	/*
	(*p)++;// 出錯 error:increment of read-only lacation '*p'
	printf("p=%d\n",*p);
	*/
}
輸出結果:

這裏我們發現指針p 我們可以隨便調整指向哪塊已知的內存空間,但是不能通過 給*p 複製來改變指針所指的對象。

int const *p 和上面const int *p  效果一樣這裏就不多說啦。

接下來說 int * const p 形式,如下測試代碼:

// int * const p 表示指針p 不可修改,但是指針p 所指向的內容可以修改
void test3()
{
	int i = 1;
	int j = 100;
	int * const p = &i;

	printf("p=%d\n",*p);

	i = 2;

	printf("p=%d\n",*p);
	/*
	p = &j;// error:assignment of read-only variable 'p'
	printf("p=%d\n",*p);
	*/
	(*p)++;
	printf("p=%d\n",*p);
	printf("i=%d\n",i);
}

輸出結果:

最後一種情況就是上面情況結合在一起const int * const p 這樣就是p 指針無法修改,p 指針所指的內容也無法修改。

C與指針第六章習題

1.

char * find_char(char const * source , char const *chars)
{
	if(source==NULL || chars==NULL)
		return NULL;
	char const * cp;
	for(;*source!='\0';source++)
	{
		// 這裏每次遍歷chars 中內容
		for(cp=chars;*cp!='\0';cp++)
		{
			if(*source == *cp)
				return (char *)source;
		}
	}
	return NULL;
}
實現中發現一個問題:char a[] 與 char *a 的區別

char a[]在運行時賦值,值會從靜態區賦值到函數的棧中,對它進行修改不會產生任何問題。char *a在編譯時就確定了,a指向靜態區中的值,沒有賦值到函數棧中, 因此對指針的內容進行修改會產生錯誤。

這個問題詳細解釋:http://blog.chinaunix.net/uid-20583479-id-1920067.html
2.

char * match(char * str,char const *substr)
{
	while(*substr != '\0')
	{
		if(*str++ != *substr++)
			return NULL;
	}
	return str;
}
int Del_substr(char *str,char const *substr)
{
	char * next;
	char * orig = str;
	while(*str != '\0'){
		next = match(str,substr);
		if(next != NULL)
			break;
		str++;
	}
	if(*str == NULL)
		return 0;
	printf("outside\n");
	while((*str) != '\0')
	{
		*str = *next;
		str++;
		next++;

	}
	printf("%s\n",orig);
	return 1;
}

3.

void reverse_string(char *str)
{
	if(str == NULL)
		return;
    char *p = str;
    int count = 0;
    char ch;
    for(;*p!='\0';p++)
	{
		count++;
	}
	p = str;
	char * end = p + count -1;
	while(p < end)
	{
		ch = *p;
		*p = *end;
		*end = ch;
		p++;
		end--;
	}
	*(str+count) = '\0';
	printf("%s\n",str);
}

指向數組的指針VS指針數組

指向數組的指針:

int vector[10], *vp = vector; 這個聲明是合法的,它爲整型數組分配內存,並把vp 聲明爲指向整型的的指針。

int matrix[2][3] matrix 並不是指向整型的的指針,而是一個指向整型數組的指針,我們應該如何聲明指向數組的指針?

int (*mp)[3]這裏要帶上第二維的數據控制,不是mp指針自增操作不確定能跳過多少長度。

int matrix[2][3] = {{1,2,3},{4,5,6}};
    int *p = &matrix[0][0];
    printf("%d\n",*p);
    printf("%d\n",*++p);
    printf("%d\n",*++p);

如上代碼,指針p 指向數組中第一個元素,然後指針自增1 ,指向了第二個數字,所以上面輸出就是:1,2,3 ,我們一直要確定好一件事情就是指針類型,因爲類型決定了指針自增1是能跳動多大的距離。

int matrix[2][3] = {{1,2,3},{4,5,6}};
    int (*mp)[3];
	mp = matrix;
    printf("%d\n",(*mp)[0]);
    printf("%d\n",(*mp)[1]);
    printf("%d\n",(*++mp)[0]);

如上代碼:定義mp 爲指向擁有3個整型元素的數組的指針,當對mp 與整數相加時,該整數值根據3這個長度調整,所以mp++ 導致指針mp 指向數組下一行數組元素。

所以上述代碼輸出:1,2,4 這裏就可以告訴我們如何去對二維數組元素通過指針進行操作。

指針數組:

正如你可以創建整型數組一樣,你也可以聲明指針數組,如下面:

int *api[10] ,api 有十個元素,每個元素是指向int 型的指針。

再看個複雜點結構:

char const *keyword[] = {
		"do",
		"for",
		"if",
		"register",
		"return",
		"switch",
		"while"
    };

keyword 是一個指針數組,數組中每個元素都指向一個char型數組。當我們需要查找某個關鍵字時可以遍歷該指針數組,如下:

int lookup_keyword(char const * const desired_word,char const *keyword_table[],int const size)
{
	char const **kwp;
	/*
	char (*p)[10];// 這裏搞清楚類型啊,keyword_table 是char **
	*/
	// 查找kewword_table中每個單詞
	for(kwp = keyword_table;kwp < keyword_table + size;kwp++){

		printf("%s\n",*kwp);
		*kwp = "hello";//數組中內容可以改變,所以*kwp 可以指向別的內容
		if(strcmp(desired_word,*kwp) == 0){
			return kwp - keyword_table;
		}
	}
	return -1;
}

這裏需要注意爲什麼kwp 定義爲指針的指針? 分析一下,keyword_table 是數組起始位置是指針,而數組中元素也是指針,所以當要引用數組中元素時必須定義爲指針的指針來遍歷該數組。

如果上述結構定義爲二維數組這樣:

   char const keywordMatrix[][9]={
		"do",
		"for",
		"if",
		"register",
		"return",
		"switch",
		"while"
    };

實現上述查找相同功能則需要進行改動:

int lookup_keywordMatrix(char const * const desired_word,char const (*keyword_table)[9],int const size)
{
	char const (*kwp)[9];
	for(kwp=keyword_table;kwp<keyword_table+size;kwp++)
	{
		if(strcmp((char *)kwp,desired_word) == 0)
		{
			return kwp - keyword_table;
		}
	}
	return -1;
}

首先傳參就需要改變,這裏定義的 char const(*keyword_table)[9] 是指向char型數組的指針,定義kwp同樣需要這樣爲:char const (*kwp)[9] ,

所以在使用strcmp 函數時需要類型強制轉換。

小結:

數組名是指向數組第一個元素的指針。這裏有兩個例外,sizeof返回整個數組佔用的字節而不是一個指針所佔用的字節。

int a[] 對 &a 操作返回是指向整個數組的指針。

指針和數組不相等。當我們聲明一個數組時,同時就分配了內存空間,但是聲明一個指針時,只是分配了容納指針本身空間。

當數組名作爲函數參數傳遞的,實際傳遞給函數是指向數組第一個元素的指針。 函數所接收的參數實際爲原參數的拷貝,所以函數可以對其進行操縱不影響實際參數,但是執行期間修改數組元素會影響原先數組元素。

結構體與內存分配:

結構體最基本的兩種訪問方式,關於內存分配,C語言中使用是malloc 和 free 。

malloc函數從內存池中提取一塊合適的內存,並向調用程序返回一個指向這塊內存的指針。你需要自己手動對這塊內存進行初始化,malloc函數分配是一塊連續的內存,

使用malloc函數時一定要注意malloc分配內存空間是否成功,如果不成功malloc函數會返回NULL,所以好的編程習慣一定是檢查分配內存空間。

此外malloc函數返回是void * 指針,因爲這個返回類型問題,我們使用malloc經常會需要強制類型轉換。

動態內存常見錯誤:

NULL指針解引用操作、分配內存操作越界、釋放並非動態分配內存、釋放一塊動態分配內存的一部分、動態內存釋放後繼續使用等。

通過實際對單向鏈表操作來熟悉結構體和內存分配。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;

typedef struct LinkList{
	int value;
	LinkList * next;
}*ListPoint;

void insert_Node(LinkList **head,int value)
{
	ListPoint pre,current;
	pre = NULL;
	current = *head;
	while(current && current->value < value)
	{
		pre = current;
		current = current->next;
	}
	LinkList * new_node = (LinkList *)malloc(sizeof(LinkList));
	//好的編程習慣需要每次分配內存檢查
	if(new_node == NULL)
	{
		printf("malloc memory error !!!");
		return;
	}
	new_node->value = value;
	new_node->next = current;
	// 意味着插入鏈表起始位置
	if(pre == NULL)
	{
		printf("test here\n");
		*head = new_node;

	}
	else{
		pre->next = new_node;
	}
}

void Print_LinkList(LinkList *head)
{
	if(head == NULL)
	{
		printf("empty LinkList\n");
		return;
	}
	while(head !=NULL)
	{
		printf("%d",head->value);
		head = head->next;
	}
}

int main()
{

	int arr[6] = {3,2,1,6,4,5};
	ListPoint head = NULL;
	for(int i=0;i<6;i++)
	{
		insert_Node(&head,arr[i]);
	}
	Print_LinkList(head);

	for(int i=0;i<6;i++)
	{
		printf("haha\n");
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章