[英]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 種情況下,數組表達式不會轉換為指針值:
當它是sizeof
運算符的操作數時。 sizeof an_array
產生數組的大小,而不是指針的大小。
當它是一元&
運算符的操作數時。 &an_array
產生整個數組對象的地址,而不是某些(不存在的) char*
指針對象的地址。 它的類型是“指向 6 個char
數組的指針”,或char (*)[6]
。
當它是用作數組對象的初始值設定項的字符串文字時。 在上面的例子中:
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.