C語言動態內存經典筆試題分析
文章目錄
- C語言動態內存經典筆試題分析
- 1. 題目一
- 2. 題目二
- 3. 題目三
- 4. 題目四
1. 題目一
void GetMemory(char *p){p = (char *)malloc(100);}
void Test(void){char *str = NULL;GetMemory(str);strcpy(str, "hello world");printf(str);}
運行Test函數會有什么結果?
代碼運行時會崩潰
上述代碼中出現的問題
- malloc開辟的空間沒有釋放,內存泄漏
- 代碼會崩潰,即使GetMemory函數返回,str依然為NULL
- GetMemory函數無法把malloc開辟的100個字節帶回來
TIP:上述代碼中的printf(str);沒有錯,與printf(“abcdef”); printf(“%s”,str);一樣,都是將數組的首元素地址傳給kbd>printf
代碼出現的主要問題是GetMemory函數返回,str依然為NULL
分析:
傳給GetMemory函數的只是str中的值,并不是str的地址,使用為傳值調用,傳值調用形參的改變并不會改變實參,形參只是實參的臨時拷貝,所以str中的值不會改變,在使用strcpy時,對NULL指針解引用了,導致程序崩潰
上述代碼的修改:
void GetMemory(char** p)
{*p = (char*)malloc(100);
}
void Test(void)
{char* str = NULL;GetMemory(&str);strcpy(str, "hello");printf(str);free(str);str = NULL;
}
2. 題目二
void GetMemory(char** p, int num)
{*p = (char*)malloc(num);
}
void Test(void)
{char* str = NULL;GetMemory(&str, 100);strcpy(str, "hello");printf(str);
}
運行Test函數會有什么結果?
正常打印hello
分析:
與題目一類似,不過這段代碼時將,str的地址傳給了GetMemory函數,函數形參使用二級指針存放指針的地址,并將開辟好的空間的地址賦值給p,也就是str,代碼并沒有明顯問題,并不會像代碼一一樣崩潰
只不過這段代碼沒有釋放malloc開辟的空間,會導致內存泄漏
上述代碼的修改:
void GetMemory(char** p, int num)
{*p = (char*)malloc(num);
}
void Test(void)
{char* str = NULL;GetMemory(&str, 100);strcpy(str, "hello");printf(str);free(str);str = NULL;
}
3. 題目三
char* GetMemory(void)
{char p[] = "hello world";return p;
}
void Test(void)
{char* str = NULL;str = GetMemory();printf(str);
}
運行Test函數會有什么結果?
代碼打印的結果是不確定的
分析:
這段代碼錯就錯在返回了局部變量的地址,局部變量的生命周期在出作用域就結束了,也就是在調用完GetMemory函數之后,p就被銷毀了,還給了操作系統,在下面用指針接收了局部變量的地址時,這個指針就是野指針,代碼打印會出不確定的結果
可以簡化下這段代碼:
int* test()
{int n = 10;return &n;
}
int main()
{int* ret = test();printf("hello\n");printf("%d", *ret);return 0;
}
打印出的結果為不確定的
分析:
上述代碼就是明顯返回了局部變量的地址,如果沒有 printf(“hello\n”);這段的話,代碼雖然能正常運行但是不代表沒錯,printf(“hello\n”);這段的話破壞了函數的棧幀空間,導致打印的值不確定
在運行代碼的時候,main函數開辟一塊空間,再為TestTest函數開辟一快空間,再為TestGetMemort函數開辟一快空間,GetMemort函數中有一個字符數組p,并且返回p的地址,數組名就是首字符地址,調用GetMemort函數結束,GetMemort函數被銷毀,還給了操作系統,當在打印數組之前,出現了其他代碼,就會破壞函數的棧幀空間,導致打印的值為不確定的
4. 題目四
void Test(void)
{char* str = (char*)malloc(100);strcpy(str, "hello");free(str);if (str != NULL){strcpy(str, "world");printf(str);}
}
代碼運行結果正常打印world
運行結果沒錯不代表結束沒錯
分析:
在上述代碼中,使用strcpy將“hello”拷貝到str中,然后使用free釋放了malloc開辟的空間,空間沒了,但是空間的地址還在,str沒有置NULL,此時str就是野指針,對野指針進行訪問就是非法訪問,因為野指針指向的一塊不屬于它的空間