2015-07-19 60 views
-5

我正在遵循一個編程範例教程,並做一些與內存相關的練習。我剛剛提取了兩個問題(請忘記代碼是什麼樣子,對不起,這是不好的代碼,但我只是想從中學到指針的東西)。原始代碼使得lsearch儘可能通用,因此它使用所有指針。數組元素是否在內存中不斷保存?

  1. 我有關於訪問數組的一個元素的問題:

    當我們訪問數組a[]的第四個元素,我們使用*(a+3); 當我們訪問字符串數組char * names[]的第3個元素時,我們使用*(char**)((char*)names+sizeof(char*)*2)。 我們是否假設數組的元素被連續保存在內存中?

  2. 問題2有關訪問字符串數組元素:爲什麼我們需要在names(基地址)前面加上(char*),我儘量不添加(char*)和代碼與分段錯誤崩潰。我打印的尺寸爲(char*),它是8,而sizeof(names)是32.爲什麼我們在這裏需要(char*)?我真的認爲地址是32位,如果我們把它轉換成8位,計算機應該很難找到它指向的元素。 謝謝

#include<iostream> 
#include<string> 
#include<typeinfo> 
int main() 
{ 
     int a[5] = {1,2,3,4,5}; 
     std::cout << *(a+3) << std::endl; 


     char* names[4] = {"James", "Dustin", "Rich", "Ed"}; 
     std::cout << *(char**)((char*)names+2*sizeof(char*)) << std::endl; 
     //std::cout << sizeof(names) << " " << sizeof(char*) << std::endl; 
} 

下面是從斯坦福107

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

int StrCmp(void* vp1, void* vp2) 
{ 
     char *s1 = *(char**)vp1; 
     char *s2 = *(char**)vp2; 
     if(strcmp(s1,s2)==0){ 
       return 0; 
     } 
     return 1; 
} 

char ** lsearch(void *key, void* base, int size, int elemSize, int (*cmpFn)(void *, void *)) 
{ 
     for(int i=0; i<size; ++i){ 
       char* addr = (char*) base + elemSize *i; 
       if (cmpFn(key, addr)==0) return (char**)addr; 
     } 
     return NULL; 
} 

int main() 
{ 
     char *notes[] = {"Ab", "F#", "B", "Gb", "D"}; 
     char* favorStr = "F#"; 
     char ** found = lsearch(&favorStr,notes,5,sizeof(char*),StrCmp); 
     if(found!=NULL) cout << *(char**)found << endl; 
     else cout << "not found" << endl; 
} 
+0

'sizeof'以字節爲單位返回大小,而不是位(而你的指針顯然是64位寬)。 – melpomene

+2

這個問題顯示了很少的前期研究,其中一些是錯誤的。檢查標準將回答你關於連續性的問題。檢查數組和/或指針上的一些(更好的)教程可以消除像* *(char **)((char *)名稱+ 2 * sizeof(char *))' –

+0

這樣的神祕構造。另外,如果要使用C++,你應該避免使用舊的C風格的字符串。並不是說他們和你的帖子一樣困難,但爲什麼生活在過去?使用現代C++特性,您根本不必擔心事物是否連續,指針有多寬等。 –

回答

3

原編碼根據C++標準(8.3.4陣列)

1 ...數組類型的對象包含連續分配d非空集類型T.

N個子對象應用到從你的信息數組定義而只表示四個指針(數組的元素)以字符串文字中的存儲器中連續程度被分配的 。這種內存範圍本身不包含字符串文字。

在C++中,字符串文字具有常量字符數組的類型。當它們被用作初始值設定這樣

char* names[4] = {"James", "Dustin", "Rich", "Ed"}; 

然後它們被隱式轉換成指向該陣列的第一個元素const char *類型的指針。

所以它會更好,如果你想輸出數組的第三個元素(考慮到它是一個指針)來定義像

const char* names[4] = {"James", "Dustin", "Rich", "Ed"}; 

數組,那麼你必須寫

std::cout << (const void *) (names + 2) << std::endl; 

如果要輸出的字符串字面量由該元素指向你只要簡單地寫

std::cout << *(names + 2) << std::endl; 

至於表達

*(char**)((char*)names+2*sizeof(char*)) 

然後子表達式(char*)names重新解釋類型char *[4] like an array pf type的char [4 *的sizeof(字符*)]的陣列。所以表達

(char*)names+2*sizeof(char*) 

產生相同的值作爲表達式

(names + 2) 

例如語句

​​

std::cout << (void *)((char*)names + 2*sizeof(char*)) << std::endl; 

將產生相同的輸出

我認爲,如果運行這個示範項目將更加清晰

#include <iostream> 

int main() 
{ 
    const char* names[4] = {"James", "Dustin", "Rich", "Ed"}; 

    for (size_t i = 0; i < 4; i++) 
    {   
     std::cout << (const void *)(names + i) << std::endl; 
    } 

    std::cout << std::endl; 

    for (size_t i = 0; i < 4; i++) 
    {   
     std::cout << (const void *)*(names + i) << std::endl; 
    } 

    std::cout << std::endl; 

    for (size_t i = 0; i < 4; i++) 
    {   
     std::cout << (const void *)((char *)names + i * sizeof(char *)) << std::endl; 
    } 

    std::cout << std::endl; 

    for (size_t i = 0; i < 4; i++) 
    {   
     std::cout << (const void *)*((const char **)((const char *)names + i * sizeof(char *))) << std::endl; 
    } 

    std::cout << std::endl; 
} 

程序輸出可能看起來像

0x7fffc0f639f0 
0x7fffc0f639f8 
0x7fffc0f63a00 
0x7fffc0f63a08 

0x40d884 
0x40d88a 
0x40d891 
0x40d896 

0x7fffc0f639f0 
0x7fffc0f639f8 
0x7fffc0f63a00 
0x7fffc0f63a08 

0x40d884 
0x40d88a 
0x40d891 
0x40d896 

在這個程序表達式(names + 0)(names + 1)(names + 2)(names + 3)是地址相應的索引爲0, 1, 2, 3的數組名稱的元素。 表達式*(names + 0),*(names + 1),*(names + 2),*(names + 3)是存儲在這些元素中的值。

表達式(char *)names + i * sizeof(char *)其中我在範圍0-3 中的數字元素是相同的地址。和表達式 *((const char **)((const char *)names + i * sizeof(char *)))給出數組元素的相同值。

+0

謝謝!我試過std :: cout << names + 2 << std :: endl;它實際上給出了與std :: cout <<(const void *)(names + 2)<< std :: endl; – daydayup

+1

@daydayup對不起。我犯了一個錯字。看到我更新的帖子。:) –

+0

謝謝@VladfromMoscow!我可以問,在std :: cout <<(char *)名稱+ 2 * sizeof(char *)<< std :: endl; ,爲什麼我們需要在名稱前添加(char *)?我只是認爲默認名稱應該是char *類型,因爲我們已經定義了char *名稱[4]。 – daydayup