C++ 一些題型

 

1. 常量指針

const char * p;  // 字符是常量,指針 p 可以改變,指向的常量值不能改變
char const *p;  // 同上
char* const p;  // 指針p 是常量, 不能改變指針的值

2. 字符數組變量有各自的內存空間,指針指向相同的區域

char str1[] = "abc";
char str2[] = "abc";

const char str3[] = "abc";
const char str4[] = "abc";

char* str5 = "abc";
char* str6 = "abc";

const char* str7 = "abc";
const char* str8 = "abc";


std::cout << (str1 == str2) << std::endl;  // 0
std::cout << (str3 == str4) << std::endl;  // 0
std::cout << (str5 == str6) << std::endl;  // 1
std::cout << (str7 == str8) << std::endl;  // 1

3. 函數中字符串數組的大小 sizeof

void testChar(char str[]){
    cout << sizeof(str) << endl;  // 4
    cout << strlen(str) << endl;  // 11
}

char str[] = "ahkadkgjsal";
testChar(str);  // str 在函數中是以指針形式保存,爲 4 個字節

cout << sizeof(str) << endl;  // 12

4. &a + 1  偏移1 個數組的大小

int main(){
    int a[5] = {1, 2, 3, 4, 5};
    int* ptr = (int*)(&a + 1);
    cout << *(ptr-1) << endl;  // 5
}

*(a+1)就是a[1],*(ptr-1)就是a[4],執行結果是2,5
&a+1不是首地址+1,系統會認爲加一個a數組的偏移,是偏移了一個數組的大小(本例是5個int)
int *ptr=(int *)(&a+1);
則ptr實際是&(a[5]),也就是 a+5

5.下列代碼存在的問題

int  main()
{

char a;
char *str=&a;
strcpy(str,”hello”);
printf(str);

return 0;

}

沒有爲str分配內存空間,將會發生異常。問題出在將一個字符串複製進一個字符變量指針所指地址。vs報錯。

6.代碼問題

char* s="AAA";   // ”AAA” 是字符串常量, 修改爲:  const chat* s = "AAA";
printf(“%s”,s);
s[0]=’B';   //  由於是常量,不能對其進行賦值
printf(“%s”,s);

7. int (*s[10])(int) 表示

函數指針數組, 每一個指針指向  int function(int param)  函數

char (*str) [10];  // *str 是一個數組指針,指向數組的指針
char *str[10];     // *str 是一個指針數組,存放的所有的元素都是指針

8.sizeof()  和字符數組初始化沒有關係;  strlen() 與初始化相關;

char s[10];
cout << sizeof(s) << endl;  // 10
cout << strlen(s) << endl;  // 25  隨意的一個值 

9. 下列代碼的錯誤

void GetMemory( char **p, int num )

{
 *p = (char *) malloc( num );
}

 
void Test( void )

{
 char *str = NULL;
 GetMemory( &str, 100 );
 strcpy( str, "hello" );
 printf( str );

}

存在2處問題:

1. 未對malloc的內存進行釋放

2. 未判斷內存是否申請成功;

void GetMemory(char **p,int num)
{                          
//p,指向指針的指針,*p,p指向的指針(即str),**p,最終的對象,str指向的單元

*p=(char *)malloc(num);  //申請空間首地址付給傳入的被p指向的指針,即str
if (*p == NULL){
    cout <<" 申請內存失敗"  << endl;  // 2. 判斷內存是否申請失敗
} 

}

int main()
{
char *str=NULL;
GetMemory(&str,100);   //傳入指針變量本身的地址
strcpy(str,”hello”);
free(str);  //1.  釋放內存
str = NULL;
}

10. 下列代碼的不足

void Test( void )

{

 char *str = (char *) malloc( 100 );

 strcpy( str, "hello" );

 free( str );

 ... //省略的其它語句

}

1. 沒有對內存是否申請成功進行判斷

2, free(str) 後沒有置 str 爲空,導致可能變成一個野指針

void Test( void )

{

 char *str = (char *) malloc( 100 );
  
  if (str == NULL){
        cout << "內存申請失敗"  << endl;
        return;
}

 strcpy( str, "hello" );

 free( str );
  str = NULL;

 ... //省略的其它語句

}

11. 兩個數字交換

void swap1(int* p1, int* p2){  // 存在問題
    int* temp;  //  新建1 個指針,但是沒有分配內存,temp= p1 是指向而不是拷貝
    temp = p1;
    p1 = p2;
    p2 = temp;
}

void swap2(int* p1, int* p2){  // 指針傳遞
    int temp;
    temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}

void swap3(int &p1,int &p2){  // 引用傳遞
    int temp;
    temp = p1;
    p1 = p2;
    p2 = temp;
}

void swap4(int *p1, int* p2){
    int *temp;
    *temp = *p1;
    *p1 = *p2;
    *p2 = *temp;
}
int *temp新建了一個指針(但是沒分配內存)。*temp=*p不是指向而是拷貝。
把*p所指向的內存的值(也就是a 的值)拷貝到*temp所指向內存裏了。
但是int *temp不是不分配內存嗎?的確不分配,於是系統在拷貝時臨時給了一個隨機地址,讓它存值。
分配的隨機地址是個“意外”,且函數結束後不回收,造成內存泄漏。

12. char  str[]  和  char* str  區別

char* strA(){
    char str[] = "hello world";
    return str;
}
//  str[]  是局部變量, 對應內存中的棧,局部變量在聲明週期結束後該變量就不存在了。返回結果不正確


const char* strB(){
    const char* str = "hello world";
    return str;
}
// 指向常量區的字符串,位於靜態存儲區,它在程序中聲明週期不變,返回結果正確

修改第一個程序: 使用static 開闢一段靜態的存儲空間

char* strA(){
    static char str[] = "hello world";
    return str;
}

13. 判斷程序運行結果的輸出

int arr[] = {1,2,3,4,5,6,7,8}; // 定義 1 個數組

int *p=arr;

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


第三行,p++裏的 ++ 是最後才運算,所以先執行*p+=123,也就是arr的第0個元素被賦值爲  124
此時arr變成{123,2,3,4,5,6,7,8} ,然後是p++,此時 *p 已經是等於arr的第1個元素了,也就是2
第四行,在執行printf時,括號裏的參數是從右往左的順序進行讀取的,也就是說先執行 *(++p),也就是p先加一再指針,指向的是arr第2個元素3,然後在執行*p,還是3
最後顯示的內容就是
3,3


14.輸出結果

unsigned char* p1;
unsigned long* p2;
p1 = (unsigned char*)0x801000;
p2 = (unsigned long*)0x810000;
p1 + 5= ???
p2 + 5 = ???

p1 相當於加上 5 位, 0x801005  (十六進制)

p2 相當於加上 5 *4 = 20 位, 0x810014

15. 找出下列代碼的錯誤

將字符串倒序輸出

#include"string.h"   

main()   
{   
char*src="hello,world";  
char* dest=NULL;   
int len=strlen(src);   
dest=(char*)malloc(len);      
char* d=dest;   
char* s=src[len];           
while(len--!=0)   
    d++=s--;          
printf("%s",dest);   
return 0;   
}   

程序有4 個錯誤的地方

int main()   

{   
 const char* src = "hello,world";   
 int len = strlen(src);   

 char* dest = (char*)malloc(len+1);// 1. 要爲 分配一個內存空間 ,+1 存放'\0'   
  char* d = dest;   // 作爲移動的指針
 const char* s = &src[len-1];          // 2. 指向最後一個字符  
 while( len-- != 0 )   

      *d++=*s--;  // 賦值操作  

 *d = '\0';           //3.尾部要加’\0’   

 printf("%sn",dest);    

free(dest);        // 4. 使用完,應當釋放空間,以免造成內存匯泄露
dest = NULL;   //防止產生野指針 

return 0;  
 }

16.程序的內存分配:

1、棧區(stack)—由編譯器自動分配釋放,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧。
2、堆區(heap)—一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收。注意它與數據結構中的堆是兩回事,分配方式倒是類似於鏈表,呵呵。
3、全局區(靜態區)(static)—全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。程序結束後由系統釋放。
4、文字常量區常量字符串就是放在這裏的。程序結束後由系統釋放。
5、程序代碼區—存放函數體的二進制代碼

int a=0;  //全局初始化區
char *p1; //全局未初始化區
main()
{
int b;          // 棧
char s[]=”abc”; // 棧
char *p2;       // 棧
char *p3=”123456″; //  123456\0在常量區, p3在棧上。
static int c=0; //  全局(靜態)初始化區
p1 = (char*)malloc(10);
p2 = (char*)malloc(20); //  分配得來得10和20字節的區域就在堆區。
strcpy(p1,”123456″);    //  123456\0放在常量區,編譯器可能會將它與p3所向”123456″優化成一個地方。
}

17.根據要求定義

a) 一個整型數                             (An integer)
b) 一個指向整型數的指針          (A pointer to an integer)
c) 一個指向指針的的指針,它指向的指針是指向一個整型數(A pointer to a pointer to an integer)
d) 一個有10個整型數的數組(An array of 10 integers)
e) 一個有10個指針的數組,該指針是指向一個整型數的(An array of 10 pointers to integers)
f) 一個指向有10個整型數數組的指針(A pointer to an array of 10 integers)
g) 一個指向函數的指針,該函數有一個整型參數並返回一個整型數(A pointer to a function that takes an integer as an argument and returns an integer)
h) 一個有10個指針的數組,該指針指向一個函數,該函數有一個整型參數並返回一個整型數

( An array of ten pointers to functions that take an integer argument and return an integer )

答案是:
a) int a;                         // An integer
b) int *a;                       // A pointer to an integer
c) int **a;                     // A pointer to a pointer to an integer
d) int a[10];                 // An array of 10 integers
e) int *a[10];               // An array of 10 pointers to integers
f) int (*a)[10];             // A pointer to an array of 10 integers
g) int (*a)(int);           // A pointer to a function a that takes an integer argument and returns an integer
h) int (*a[10])(int);    // An array of 10 pointers to functions that take an integer argument and return an integer

18.代碼輸出的值:

void foo()
{
	unsigned int a = 6;
	int b = -20;
	(a + b > 6) ? puts(" > 6 ") : puts("< 6 ");  //  > 6 
	cout << (a + b) << endl; // 4294967282
}

C語言中的整數自動轉換原則,這無符號整型問題的答案是輸出是 ">6″。原因是當表達式中存在有符號類型和無符號類型時所有的操作數都自動轉換爲無符號類型。, 所有 -20 會轉換成一個非常大的數字

19評價代碼

unsigned int zero = 0;
unsigned int compzero = 0xFFFF;


對於一個int型不是16位的處理器爲說,上面的代碼是不正確的。應編寫如下:
unsigned int compzero = ~0;

說明:~是位運算符,是取反的意思,即二進制位0變1,1變0;
unsigned int compzero = 0xFFFF;表示1111 1111 1111 1111,對於int型不是16位的處理器來說,上面的代碼是不正確的。
unsigned int compzero=~0;(以16位處理器來說明)表示將0的二進制位0000000000000000取反,變成1111111111111111,對不是16位處理器的也是正確的。

20.代碼執行結果:

int a = 5, b = 7, c;
c = a+++b;

代碼執行爲:  c = a++  + b;  // 先執行 a++

輸出爲:   a =,6; n = 7; c = 12

21.輸出結果

typedef union {long i; int k[5]; char c;} DATE;
struct data { int cat; DATE cow; double dog;} too;
DATE max;
則語句 printf(“%d”,sizeof(struct date)+sizeof(max));的執行結果是?

答 、結果是:52。DATE是一個union, 變量公用空間. 裏面最大的變量類型是int[5], 佔用20個字節. 所以它的大小是20
data是一個struct, 每個變量分開佔用空間. 依次爲int4 + DATE20 + double8 = 32.
所以結果是 20 + 32 = 52.
當然…在某些16位編輯器下, int可能是2字節,那麼結果是 int2 + DATE10 + double8 = 20

22,問函數既然不會被其它函數調用,爲什麼要返回1?


int main()
{
int x=3;
printf(“%d”,x);
return 1;
}
答:mian中,c標準認爲0表示成功,非0表示錯誤。具體的值是某中具體出錯信息

23.結果輸出

	unsigned short A = 10;
	printf("~A = % u\n", ~A); // 4294967282 

	char c = 128;
	printf("c = % d\n", c); // -128


第一題,~A =0xfffffff5 ,int 值 爲-11,但輸出的是uint。所以輸出4294967285
第二題,c=0×10,輸出的是int,最高位爲1,是負數,所以它的值就是0×00的補碼就是128,所以輸出-128。
這兩道題都是在考察二進制向int或uint轉換時的最高位處理。

24.long a=0×801010;a+5=?
答:0×801010用二進制表示爲:“1000 0000 0001 0000 0001 0000”,十進制的值爲8392720,再加上5就是8392725

25.結構體的大小

偏移量指的是結構體變量中成員的地址和結構體變量地址的差。

結構體大小等於最後一個成員的偏移量加上最後一個成員的大小。

 

(1)結構體變量中成員的偏移量必須是成員大小的整數倍(0被認爲是任何數的整數倍) 

(2)結構體大小必須是所有成員大小的整數倍,也即所有成員大小的公倍數。

struct stru{
	char a;   //第一個成員a的偏移量爲0
	int b;    //第二個成員b的偏移量是第一個成員的偏移量加上第一個成員的大小(0+1=1,但是必須是第二個變量類型長度4的倍數,即爲4)
	float c;  //第三個成員c的偏移量是第二個成員的偏移量加上第二個成員的大小(4+4=8,但是必須是第三個變量類型長度4的倍數,即爲8)
	double d; //第四個成員d的偏移量是第三個成員的偏移量加上第三個成員的大小(8+4=12,但是必須是第四個變量類型長度8的倍數,即爲16)  
};
//最後計算結構體大小等於最後一個成員(第四個)的偏移量(16)加上最後一個成員的大小(8)。
//即16+8(double)=24
//另外結構體大小必須是所有成員大小的整數倍,也即所有成員大小的公倍數。
//大於等於24並且1,4,4,8的公倍數------>24

struct stru{
	char a;   //第一個成員a的偏移量爲0
	int b;    //第二個成員b的偏移量是第一個成員的偏移量加上第一個成員的大小(0+1=1,但是必須是第二個變量類型長度4的倍數,即爲4)
	float c;  //第三個成員c的偏移量是第二個成員的偏移量加上第二個成員的大小(4+4=8,是第三個變量類型長度4的倍數,即爲8)
	double d; //第四個成員d的偏移量是第三個成員的偏移量加上第三個成員的大小(8+4=12,但是必須是第四個變量類型長度8的倍數,即爲16) 
	int e;	  //第五個成員e的偏移量是第四個成員的偏移量加上第四個成員的大小(16+8=24,是第五個變量類型長度4的倍數,即爲24)  
};
//最後計算結構體大小等於最後一個成員(第五個)的偏移量(24)加上最後一個成員的大小(4)。
//即24+4(double)=28
//另外結構體大小必須是所有成員大小的整數倍,也即所有成員大小的公倍數。
//大於等於28並且1,4,4,8,4的公倍數------>32


26.宏定義最大值

#define MAX(a, b) ((a) > (b) ? (a): (b))


cout << MAX(1.2, 2.4) << endl;

27.判斷操作系統是32 位還是 64 位

1. 使用庫文件:

#include <iostream>
#include <Windows.h>

using namespace std;

void is64BitOS() {
	SYSTEM_INFO cur_system_info;
	GetNativeSystemInfo(&cur_system_info);

	WORD system_str = cur_system_info.wProcessorArchitecture;
	if (system_str == PROCESSOR_ARCHITECTURE_AMD64 || system_str == PROCESSOR_ARCHITECTURE_IA64) {
		cout << "this is 64 OS"  << endl;
	}else cout << "other OS" << endl;	
	
}

2. 使用指針判斷:指針在32位操作系統時 4個字節,在64位是8個字節

int *p;
if (sizeof(p) == 4) std::cout << "32位操作系統" << std::endl;
else cout << "64 位操作系統" << endl;

28.判斷是大端還是小端的

大端模式:數據的低位保存在內存中的高地址中,數據的高位保存在內存中的低地址當中。

小端模式:數據的低位保存在內存中的低地址中,數據的高位保存在內存中的高地址當中。

將0x12345678寫入到以1000h開始的內存中,這裏0x12346578中0x12~0x78的地址是從高到低

如果,我們的機器是小端存儲的話,結果爲:

數據      地址
0x78        1000H
0x56        1001H
0x34        1002H
0x12        1003H
如果我們的機器是大端存儲的話,結果爲:

數據      地址
0x12        1000H
0x34        1001H
0x56        1002H
0x78        1003H

https://blog.csdn.net/wang57389675/article/details/52526251

優勢點:

小端模式:強制轉換數據不需要調整字節內容,1、2、4字節的存儲方式一樣。

大端模式:符號位的判定固定爲第一個字節,容易判斷正負。

void isBigEndian(){
    int a = 0x12345678;
    char data = *(char *)(&a); // 強制類型轉換成char單字節,data 指向a的起始字節(低字節)
    if (data == 0x12) cout << "小端模式" << endl; 
    else cout << "大端模式" << ednl;
}

29.C++ 實現 回調函數

通過一個函數指針調用一個函數

其中:

typedef int (*PFunc)(int);  // 定義

去掉typedef   int (*PFunc)(int) 是 一個指向 返回類型爲 int, 參數是  int 類型的函數;

typedef int (*PFunc)(int);  所以:  PFunc是函數指針類型的  別名;

類似於  typedef  unsigned int uint;  用 unit  代替  unsigned int ;

PFunc func;   func是一個返回類型爲 int , 參數是int 類型的函數

typedef int (*PFunc)(int);  // PFunc 是函數指針

int getNum(int n) {
	return n*10;
}

int main(){
    
    PFunc multi = getNum;
	cout << multi(10) << endl;

    return 0;
}

 

 

 

 

 

 

 

 

 

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