簡體   English   中英

指針是數組嗎?

[英]Are pointers arrays?

這是我難以理解的代碼:

char* myPtr = "example";
myPtr[1] = 'x';

我如何被允許使用myPtr[1] 為什么我可以像在數組上一樣選擇位置? myPtr甚至不是一個數組。

觀察。 我知道查找表、文字池和字符串文字,我關心的是它是如何編譯的。 我不怎么使用指針。

任何人都可以幫忙嗎?

顯然,您假設[]運算符對某物的適用性必然意味着“某物”是一個數組。 這不是真的。 內置[]運算符與數組沒有直接關系。 []只是*+運算符組合的簡寫:根據定義, a[b]表示*(a + b) ,其中一個操作數必須是指針,另一個必須是整數。

此外,當您將[]運算符應用於實際數組時,該數組首先被隱式轉換為指針類型,然后結果指針才能充當[]運算符的操作數。 這實際上意味着與您最初假設的相反:運算符[]從不與數組一起工作。 當我們到達[] ,數組已經衰減為一個指針。

作為相關的旁注,后一個細節體現在第一個 C 語言標准的一個晦澀的特性中。 在 C89/90 中,右值數組不允許數組到指針的轉換,這也阻止了[]運算符處理此類數組

struct S { int a[10]; };

struct S foo(void) { struct S s = { 0 }; return s; }

int main() 
{
  foo().a[5]; 
  /* ERROR: cannot convert array to pointer, and therefore cannot use [] */

  return 0;
}

C99 擴展了該轉換的適用性,從而使上述代碼有效。

指針保存分配給它們保存的特定數據類型的變量的內存位置地址。 正如其他人指出的那樣,它的反直覺方法需要一些學習曲線才能理解。

請注意,字符串"example"本身是不可變的,但是編譯器不會阻止對指針變量的操作,指針變量的新值更改為字符串'x'的地址(這與'example'x的地址不同'example' ),

char* myPtr = "example";
myPtr[1] = 'x';

由於 myPtr 在程序運行時引用不可變數據,它會崩潰,盡管它編譯沒有問題。

從 C 的角度來看,在這里,您正在取消引用一個可變變量。 默認情況下,在 C 中,char 指針被定義為可變的,除非通過關鍵字const明確聲明為不可變,在這種情況下,綁定變得不可分割,因此在定義指針變量后不能將任何其他內存地址分配給它。

假設你的代碼看起來像這樣,

const char *ptr ="example";
ptr[1] = 'x';

現在編譯將失敗並且您無法修改該值,因為此指針變量是不可變的。

您應該只使用字符指針來訪問字符串中的單個字符。

如果你想做字符串操作,那么我建議你聲明一個int來存儲來自標准輸入輸出的每個字符的 ASCII 值,就像這里提到的那樣,

#include<stdio.h>
int main()
{
    int countBlank=0,countTab=0,countNewLine=0,c;
    while((c=getchar())!=EOF)
    {
        if(c==' ')
            ++countBlank;
        else if(c=='\t')
            ++countTab;
        else if(c=='\n')
            ++countNewLine;
        putchar(c);
    }
    printf("Blanks = %d\nTabs = %d\nNew Lines = %d",countBlank,countTab,countNewLine);
}

查看整數如何使用 ASCII 值,以便使用 getchar() 和 putchar() 獲取和打印單個字符。

特別感謝 Keith Thompson 今天在這里學到了一些有用的東西。

它根據 C++ 標准的 §5.2.1/1 [expr.sub] 編譯:

后綴表達式后跟方括號中的表達式是后綴表達式。 其中一個表達式應具有“T 數組”或“T 指針”類型,另一個應具有無作用域枚舉或整數類型。 結果是“T”類型。 類型“T”應該是一個完全定義的對象類型。

表達式E1[E2]與(根據定義)相同*((E1)+(E2)) ,除了在數組操作數的情況下,如果該操作數是左值,則結果是左值,否則結果是左值。

由於"example"類型為char const[8]因此它可能會衰減為char const* (它曾經也衰減為char* ,但它主要是過去的遺物),這使其成為指針。

此時表達式myPtr[1]變成了定義明確的*(myPtr + 1)

要記住的最重要的事情是:

數組不是指針。

但是在 C 和 C++ 中有一些語言規則可以讓它們看起來好像是一回事。 在某些上下文中,數組類型的表達式或指針類型的表達式是合法的。 在這些上下文中,數組類型的表達式被隱式轉換以產生指向數組初始元素的指針。

char an_array[] = "hello";
const char *a_pointer = "goodbye";

an_array是一個數組對象,類型為char[6] 字符串文字"hello"用於初始化它。

a_pointer是一個指針對象,類型為const char* 您需要const因為用於初始化它的字符串文字是只讀的。

當數組類型的表達式(通常是數組對象的名稱)出現在表達式中時,它通常會隱式轉換為指向其初始(第 0 個)元素的指針。 例如,我們可以這樣寫:

char *ptr = an_array;

an_array是一個數組表達式; 它被隱式轉換為char*指針。 以上完全等同於:

char *ptr = &(an_array[0]); // parentheses just for emphasis

在 3 種情況下,數組表達式不會轉換為指針值:

  1. 當它是sizeof運算符的操作數時。 sizeof an_array產生數組的大小,而不是指針的大小。

  2. 當它是一元&運算符的操作數時。 &an_array產生整個數組對象的地址,而不是某些(不存在的) char*指針對象的地址。 它的類型是“指向 6 個char數組的指針”,或char (*)[6]

  3. 當它是用作數組對象的初始值設定項的字符串文字時。 在上面的例子中:
    char an_array[] = "hello";
    字符串文字"hello"被復制到an_array 它不會衰減為指針。

最后,還有一個語言規則可以讓數組看起來好像是“真正的”指針:調整使用數組類型定義的參數,使其真正是指針類型。 您可以定義一個函數,如:

void func(char param[10]);

這真的意味着:

void func(char *param);

10被默默地忽略。

[]索引運算符需要兩個操作數,一個指針和一個整數。 指針必須指向數組對象的元素。 (獨立對象被視為 1 元素數組。)表達式

arr[i]

根據定義相當於

*(arr + i)

將整數添加到指針值會產生一個新的指針,該指針在數組中向前i元素。

comp.lang.c FAQ 的第 6 節對所有這些內容都有很好的解釋。 (它適用於 C++ 以及 C;這兩種語言在這方面的規則非常相似。)

在 C++ 中,您的代碼在編譯期間生成警告:

{
  //char* myPtr = "example";  // ISO C++ forbids converting a string 
                              // constant to ‘char*’ [-Wpedantic]

  // instead you should use the following form
  char myPtr[] = "example";  // a c-style null terminated string

  // the myPtr symbol is also treated as a char*, and not a const char*

  myPtr[1] = 'k';  // still works,  

  std::cout << myPtr << std::endl;  // output is 'ekample'
}

另一方面, std::string 更加靈活,並且具有更多功能:

 {
   std::string myPtr = "example";

   myPtr[1] = 'k';  // works the same

   // then, to print the corresponding null terminated c-style string
   std::cout << myPtr.c_str() << std::endl;

   //  ".c_str()" is useful to create input to system calls requiring
   //   null terminated c-style strings
 }

abc[x] 的語義是“向 abc 添加 x*sizeof(type)”,其中 abc 是任何內存指針。 數組變量的行為類似於內存指針,它們只是指向分配給數組的內存位置的開頭。

因此,將 x 添加到數組或指針變量都將指向內存,這與指向 + x*sizeof 的變量相同(數組包含或指針指向的類型,例如在 int 指針或 int 數組的情況下,它是 4)

數組變量與 Keith 在評論中所說的指針不同,因為數組聲明將創建固定大小的內存塊,並且任何算法都將使用數組的大小而不是該數組中的元素類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM