代碼
#include<stdio.h>
//2D陣列的5column & & 5rows
int** fivearray(){
static int arr[5] [5] 。
for(short i = 0; i< 25; i){
**(arr i) = i;
printf("%d",**(arr i))。
}
return arr;
}
int main()
{
int **array = fivearray();
return 0;
}
這種設定陣列和回傳陣列的方式可以接受嗎? 我錯過了什么?
ERROR message
tester.c:12:12: warning: 從不兼容的指標型別回傳。
[-Wincompatible-pointer-types] return arr;
但是......現在我覺得
如果我把代碼改為
(*fivearray())[5],它確實可以作業,但為什么會這樣? 二維陣列是一個由5個指標組成的陣列,指向5個整數的陣列嗎?
uj5u.com熱心網友回復:
一個2D陣列是一個5個指標的陣列,指向5個整數的陣列嗎?
不是。
一個2D的int陣列是一個int的陣列。沒有涉及指標。
但是。
但是......在大多數情況下,當你使用一個陣列的名稱(又稱識別符號)時,它被轉換為一個指向陣列中第一個元素的指標。
由于二維陣列是一個陣列的陣列,第一個元素實際上是一個陣列。
因此,一個二維陣列的名稱將(在大多數情況下)被轉換為一個指向陣列的指標。這正是你在做的時候發生的事情。return arr;
換句話說 - 在你的例子中,它不是5個指標,而只是一個單一指標到5個int的陣列。
因此
int (*fivearray())[5] {...}
是你的函式的正確簽名,你可以這樣使用它:
int (*array ) [5] = fivearray() 。
array[3][2] = 42;
然后你有這樣的代碼:
for(short i =0; i<25; i){
**(arr i) = i;
printf("%d",**(arr i))。
}
其中**(arr i)是完全錯誤的。你可能想要:
for(short i = 0; i<25; i){
arr[i/5][i%5] = i。
printf("%d", arr[i/5][i%5] )。)
}
但在IMO中,它將更清楚地顯示為:
for(int i =0; i<5; i){
for(int j = 0; j<5; j){
arr[i][j] = i*5 j;
printf("%d"/span>, arr[i][j])。
}
}
uj5u.com熱心網友回復:
我發現制作typedefs有助于處理更復雜的回傳型別。
在這里,這可能會有幫助:
在這里,這可能會有幫助。
typedef int fivebyfivearray_t[5][5] 。
然后它可以這樣使用:
#include <stdio.h>
typedef int fivebyfivearray_t[5][5] 。
fivebyfivearray_t* fivearray(){
static fivebyfivearray_t arr;
for(short i = 0; i< 25; i) {
arr[i/5][i%5] = i; //避免未定義行為。
}
return &arr;
}
int main() {
fivebyfivearray_t* array = fivearray()。
for(short i = 0; i< 25; i) {
printf("%d
", (*array)[i/5][i%5]) 。
}
}
fivearray()函式的用戶仍然可以在不使用fivebyfivearray_t typedef的情況下自由呼叫它:
int(*array)[5] [5] = fivearray();
但是,由于該函式是用來回傳二維陣列的地址的(而不是讓指標衰減到int(*)[5]),用戶將不允許犯這樣的錯誤:
int(*array)[4] [5] = fivearray(); //編譯錯誤。
這樣做的唯一缺點是你需要解除對回傳值的參考。(*array)[y][x]。
一個更清晰的選擇可能是將復雜的資料打包在一個
結構中,并回傳一個指向該結構的指標:
#include <stdio.h>
typedef struct {
int data[5][5] 。
} fivebyfivearray_t;
fivebyfivearray_t *fivearray(){
static fivebyfivearray_t arr;
for(short i = 0; i< 25; i) {
arr.data[i/5][i%5] = i; //避免未定義行為。
}
return &arr;
}
int main() {
fivebyfivearray_t* array = fivearray()。
for(short i = 0; i< 25; i) {
printf("%d
", array->data[i/5][i%5])。)
}
}
uj5u.com熱心網友回復:
讓我們看看C標準中關于在運算式中使用陣列代號的規定(6.3.2.1 Lvalues, arrays, and function designators)
3 除非它是sizeof運算子或單數&.的運算元,或者是一個字串字面。 運算子的運算元,或者是一個用于初始化陣列的字串字面,一個型別為 "陣列 "的運算式。 型別為 "陣列型別 "的運算式被轉換為 "指標型別 "的運算式。 型別為 "陣列型別 "的運算式被轉換為型別為 "指向型別的指標 "的運算式,該運算式指向陣列物件的初始元素。 的元素,并且不是一個lvalue。如果該陣列 物件有暫存器存盤類,則該行為未被定義。
你在函式fivearray
static int arr[5][5] 。
并且在回傳陳述句中把它作為一個運算式使用
return arr;
所以陣列arr在這個回傳陳述句中被隱含地轉換為指向陣列元素型別的指標。
什么是陣列的元素型別?它的型別是int[5]。所以這個型別的物件的指標將具有int ( * )[5]的型別。
但是你指定的回傳型別是int **。
int** fivearray(){
然而,在指標型別int ( * )[5]和int **之間沒有隱式轉換。
因此,該函式的回傳型別是不正確的。你必須要寫
int ( *fivearray( void ) [5] {
static int arr[5] [5]。
// ...>
return arr;
}
現在我們來考慮一下函式中的for回圈
for(short i =0; i<25; i){
**(arr i)=i。
在這個回圈中對我們來說有趣的是運算式**( arr i )。
正如我們已經注意到的,這個運算式中使用的陣列被轉換為int ( * )[5]型別的指標。
重新參考指標運算式*( arr i )你將得到陣列的第i個 "行",即型別為int[5]的第i個元素。所以你可以把運算式改寫成
arr[i]。
它是一個一維陣列。對這個運算式應用第二個去參考運算子
它是一個一維陣列。
*( arr[i] )
這與**( arr i )相同,你將得到陣列的第一個元素,因為陣列arr[i]再次被隱式轉換為指向其第一個元素的指標。
因此這個陳述句
**(arr i) = i;
將二維陣列的每 "行 "的第一個元素設定為i的值。
但是這個陣列只有5行。另一方面,變數i被從0改變為25。所以這個陳述句
**(arr i) = i;
當變數i大于4時,試圖訪問陣列以外的記憶體。
結果,該回圈呼叫了未定義行為。
為了使其直觀明了,請考慮以下示范程式。我將陣列的第一個維度改為25,以保證不會有超出陣列的訪問。
#include <stdio.h>
int main(void)
{
int arr[35][5] = { 0 };
for ( size_t i = 0; i < 25; i )
{
**( arr i ) = i。
}
for ( size_t i = 0; i < 25; i )
{
for ( size_t j = 0; j < 5; j )
{
printf( "%d", arr[i][j] ) 。
}
putchar( '
' )。
}
return 0;
程式輸出是
0 0 0 0
1 0 0 0 0
2 0 0 0 0
3 0 0 0 0
4 0 0 0 0
5 0 0 0 0
6 0 0 0 0
7 0 0 0 0
8 0 0 0 0
9 0 0 0 0
10 0 0 0 0
11 0 0 0 0
12 0 0 0 0
13 0 0 0 0
14 0 0 0 0
15 0 0 0 0
16 0 0 0 0
17 0 0 0 0
18 0 0 0 0
19 0 0 0 0
20 0 0 0 0
21 0 0 0 0
22 0 0 0 0
23 0 0 0 0
24 0 0 0 0
你可以看到這個運算式**( arr i ) = i;只改變了陣列每 "行 "的第一個元素。
你需要的是使用兩個回圈,如
。for(short i = 0; i < 5; i ) {
for ( short j = 0 j < 5; j ) {
arr[i][j] = 5 * i j;
printf( "%d", arr[i][j] ) 。
}
}
或者,如果只使用一個for回圈,那么你需要寫
。for(short i = 0; i < 25; i){
arr[i / 5][i % 5] = i。
printf( "%d", arr[i / 5][i % 5] ) 。
}
因此,該函式將看起來像這樣
int ( *fivearray( void ) [5] {
static int arr[5] [5]。
for( short i = 0; i < 25; i){
arr[i / 5][i % 5] = i。
printf( "%d", arr[i / 5][i % 5]) 。
}
return arr;
}
最后在main中你應該寫
int ( *array ) [5] = fivearray( );
注意,在整個程式中使用像5這樣的神奇數字并不是一個好主意。
你可以為魔法數字5引入一個命名的常量,例如
enum { N = 5 };
int ( *fivearray( void ) [N] {
static int arr[N][N] 。
for( short i = 0; i < N*N; i){
arr[i / N][i % N] = i;
printf( "%d", arr[i / N][i % N]) 。
}
return arr;
}
int main( void )
{
int ( *array ) [N] = fivearray();
}
uj5u.com熱心網友回復:
我認為int**不是適合你的情況的一個符號,但更多的資訊請參考這個其他問題。int * i和int** i之間的區別。
。uj5u.com熱心網友回復:
當你有一個固定大小的函式陣列時,那么我認為最好是將其作為一個指標傳遞給該函式。這樣你就不必處理(去)分配,也不必處理函式的靜態記憶體。因為對于靜態解決方案,如果你再次呼叫這個函式,你將得到與之前相同的地址。
#include<stdio.h>/span>
//2D陣列的5column & & 5rows
int fivearray(int arr[5][5]) /span>{
if(!arr) return -1; /NULL指標檢查
for(int i = 0; i<5; i){
for(int j = 0; j<5; j){
arr[i][j] = i*5 j;
}
}
return 0;
}
int main()
{
int array[5][5] = {0};
int retVal = fivearray(array)。
printf("%d
",retVal)。
for(int i = 0; i<5; i){
for(int j = 0; j<5; j){
printf("%d", array[i][j]) 。
}
}
return 0;
}
函式中的arr[5][5]的宣告,只是一個提示,編譯器不會檢查大小是否匹配,因為它仍然只是一個被傳遞的指標。但它記錄了應該傳遞的內容。
uj5u.com熱心網友回復:
首先,不要把區域變數定義為靜態變數。 所以,你應該把你的陣列定義為:
int arr[5] [5]。
如果你希望你的陣列能夠被到處訪問,可以考慮使用malloc來分配一些記憶體。
其次,在任何地方都要堅持使用型別,即使是在回圈中。浪費一些位元會給你帶來代碼中更方便的閱讀。 因此,你應該將你的for回圈定義為:
for(int i = 0; i<25; i){/*bla bla bla*/}。
最后但最重要的是,當我們談到你的實際問題時,你不應該這樣做。這并不像哈希表那樣作業,它使用了陣列的第一指標。
你所處的觀點在這里得到了解釋。 https://beginnersbook.com/2014/01/2d-arrays-in-c-example/
但是你想達到像 "POINTER TO INT ARRAYS HASH TABLE "這樣的東西(請谷歌并點擊圖片。 你會看到很多圖片)。 如果你想達到這樣的效果。 你應該使用這樣的代碼來創建這樣一個表,其中第一個(int指標陣列)陣列的每個索引都指向另一個陣列(ints陣列):
int** arr = malloc(5 * sizeof(int*)) 。
for(int i = 0; i < 5; i ){
arr[i] = malloc(5 * sizeof(int) )。
}
編輯:作為一個建議,我建議你多學習和關注一下記憶體分配。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/315478.html
標籤:
下一篇:飄動中的自定義觸點選擇
