簡體   English   中英

指針和同名的常規變量

[英]Pointer and regular variable with the same name

在《嵌入式 C 編程》一書的“內存和指針”一章中,Mark Siegesmund 給出了以下示例:

void Find_Min_Max( int list[], int count, int * min, int * max){
    for( int i=0, min=255, max=0; i<count; i++){
        if( *min>list[i])
            *min=list[i];
        if( *max<list[i] )
            *max=list[i];
    }
}
// call like this: Find_Min_Max( table, sizeof(table), &lowest, &highest);

如果我理解正確:

  • table 是一個 int 數組,
  • count 是數組的大小
  • 調用時,&lowest 和 &highest 是想要存儲結果的 int 變量的地址
  • 函數定義中的 int * min 和 int * max 指的是指針 * min 和 * max,都指向整數類型
  • 他最后一行中定義的 &lowest 和 &highest 實際上是指向具有 int 類型變量的地址的指針

(對最后一個不是 100% 確定。)

在 for 循環中,他每次都將數組列表中的下一個 int 與指針 *min 和 *max 地址處的內容進行比較,並在必要時更新這些地址處的值。

但是在循環的定義中,他定義了min = 255,max = 0。

在我看來,這似乎是兩個尚未初始化的全新變量。 那條線應該不是

for( int i=0, *min=255, *max=0: i<count; i++){

這是書上的錯誤還是我誤解了?

這似乎是書中的一個錯誤——它確實在循環內聲明了新變量。 (提示:在出版編程書籍之前,至少要先編譯代碼……)

但即使修復了那個令人尷尬的錯誤,代碼還是很天真。 這里有更多錯誤:

  • 始終const限定未修改的數組參數。
  • 在嵌入式系統中始終使用stdint.h
  • 永遠不要使用像255這樣的幻數。 在這種情況下,請改用UINT8_MAX

以上是行業標准共識。 (也是 MISRA-C 等要求的)

此外,最正確的做法是使用size_t而不是int來表示數組的大小,但這更多是一種風格問題的評論。

此外,更好的算法是讓指針指向數組中找到的最小值和最大值,這意味着我們不僅獲取值,還獲取它們在數據容器中的位置。 查找位置是一個非常常見的用例。 它的執行速度大致相同,但我們獲得了更多信息。


因此,如果我們應該嘗試將其重寫為一些值得一讀的代碼,它會看起來像:

void find_min_max (const uint8_t* data, size_t size, const uint8_t** min, const uint8_t** max);

有點難以閱讀和使用指針到指針,但更強大。

(通常我們會用restrict微優化相同類型的指針,但在這種情況下,所有指針可能最終都指向同一個對象,所以這是不可能的。)

完整示例:

#include <stddef.h>
#include <stdint.h>

void find_min_max (const uint8_t* data, size_t size, const uint8_t** min, const uint8_t** max)
{
  *min = data;
  *max = data;

  for(size_t i=0; i<size; i++)
  {
    if(**min > data[i])
    {
      *min = &data[i];
    }
    if(**max < data[i])
    {
      *max = &data[i];
    }
  }
}

PC 使用示例:(請注意int main (void)stdio.h不應在嵌入式系統中使用。)

#include <stdio.h>
#include <inttypes.h>

int main (void)
{
  const uint8_t data[] = { 1, 2, 3, 4, 5, 4, 3, 2, 1, 0};
  const uint8_t* min;
  const uint8_t* max;

  find_min_max(data, sizeof data, &min, &max);

  printf("Min: %"PRIu8 ", index: %d\n", *min, (int)(min-data));
  printf("Max: %"PRIu8 ", index: %d\n", *max, (int)(max-data));

  return 0;
}

為 ARM gcc -O3 反匯編這個搜索算法:

find_min_max:
        cmp     r1, #0
        str     r0, [r2]
        str     r0, [r3]
        bxeq    lr
        push    {r4, lr}
        add     r1, r0, r1
.L5:
        mov     lr, r0
        ldr     ip, [r2]
        ldrb    r4, [ip]        @ zero_extendqisi2
        ldrb    ip, [r0], #1    @ zero_extendqisi2
        cmp     r4, ip
        strhi   lr, [r2]
        ldr     r4, [r3]
        ldrbhi  ip, [r0, #-1]       @ zero_extendqisi2
        ldrb    r4, [r4]        @ zero_extendqisi2
        cmp     r4, ip
        strcc   lr, [r3]
        cmp     r1, r0
        bne     .L5
        pop     {r4, pc}

仍然不是最有效的代碼,非常密集的分支。 如果目標是庫質量的代碼,我認為還有很多空間可以進一步優化。 但它也是一種專門的算法,可以找到最小值和最大值,以及它們各自的索引。

對於小數據集,最好先對數據進行排序,然后從排序的最小和最大索引中獲取最小值和最大值。 如果您打算在代碼中的其他地方出於其他目的搜索數據,那么一定要先對其進行排序,以便您可以使用二分搜索。

int i=0, min=255, max=0int i=0, *min=255, *max=0都定義了三個新變量,它們被初始化,但在循環體中使用不正確。

限制應該在循環之前初始化:

*min=255;
*max=0;
for(int i=0; i<count; i++)

或者,可以在循環之前定義新變量i ,但這不像第一個那么容易閱讀:

int i;
for(i=0, *min=255, *max=0; i<count; i++)

請注意,如果存在小於0或大於255的值,則返回的最小值和最大值將不正確。

這是代碼中的一些錯誤。 也許它應該寫成:

for( int i=0, *min=255, *max=0; i<count; i++){
        if( *min>list[i])
            *min=list[i];
        if( *max<list[i] )
            *max=list[i];
    }

暫無
暫無

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

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