數(shù)組名不等于指針?sizeof()函數(shù)求數(shù)組大小錯誤問題及解決
前言
今天在項目中需要求采樣點的數(shù)量并且遍歷,采樣點用數(shù)組存儲,自定義了一個函數(shù)想要用sizeof求其長度,然后遍歷,結(jié)果失敗了,查閱之后發(fā)現(xiàn)以下問題:
在main函數(shù)中,sizeof是可以正常工作的
#include <stdio.h> int Number[10]; int main() { int size = sizeof(Number); printf("數(shù)組大小為:%d\n",size); int len = sizeof(Number)/sizeof(int); printf("數(shù)組共有%d個數(shù)據(jù)\n",len); return 0; }
輸出:
但是在自定義函數(shù)中就不可以了,如下:
#include <stdio.h> int Number[10]; void print_1(int n[]) { int size = sizeof(n); printf("數(shù)組大小為:%d\n",size); int len = sizeof(n)/sizeof(int); printf("數(shù)組共有%d個數(shù)據(jù)\n",len); } int main() { print_1(Number); return 0; }
那么我們首先要知道sizeof函數(shù)的功能:
sizeof是獲取數(shù)據(jù)在內(nèi)存中所占用的存儲空間,以字節(jié)為單位來計數(shù)。
那么這個時候有的同學就會有問題了,兩次傳入的都是數(shù)組的首地址,為什么主函數(shù)中就可以,自定義函數(shù)中就不行呢?
得益于譚老爺子的C語言書籍普及量和銷量,很多人認為數(shù)組名就是指向數(shù)組首地址的一個指針,但其實這個說法是錯誤的!
我們用一個最簡單的例子,假設(shè)數(shù)組名是一個指針,那么:
#include <stdio.h> int Number[10]; int *Number2; int main() { int a=sizeof(Number); int b=sizeof(Number2); printf("a的大小為:%d \n b的大小為 %d\n",a,b); return 0; }
- Number是一個指針,Number2也是一個指針,正常情況下 大小都應該為8
- 但是實際的輸出確實 a=40 b=8
- 也就是說數(shù)組名在某些情況下是不等于指針的,只是在一些情況下會退化為指針
首先我們要知道,單純的數(shù)組名,不是指針
數(shù)組名是一個標識符,它標識出我們之前申請的一連串內(nèi)存空間,而且這個空間內(nèi)的元素類型是相同的——即數(shù)組名代表的是一個內(nèi)存塊及這個內(nèi)存塊中的元素類型 。
只是在大多數(shù)情況下數(shù)組名會“退化”(C標準使用的decay和converted這兩個詞)為指向第一個元素的指針。
而指針不是一種聚合類的數(shù)據(jù)結(jié)構(gòu),它保存著某一種類型的對象的地址(void*除外),也說它指向這個對象。
我們可以通過這個地址訪問這個對象。用一個圖來解釋,其中a代表了整個我們聲明的內(nèi)存塊,p僅僅指向了一個char類型的對象
char a[] = {'h' 'e' 'l' 'l' 'o'}; char b[] = {'w' 'o' 'r' 'l' 'd'}; char *p=b;
這是怎么一回事呢?
我們看一下C99標準:
C99 6.3.2.1 Lvalues, arrays, and function designators 中第三段是這樣說的:
Except when it is the operand of the sizeof operator or the unary & operator, or is a
string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
the array object and is not an lvalue. If the array object has register storage class, the
behavior is undefined.
這段話的意思是: 數(shù)組名只有在
- sizeof 運算符
- 取址 & 運算符
- 字符串常量初始化的數(shù)組 Str[]=“abcdef”
這三種情況下不會發(fā)生退化(array decay)
其余情況下調(diào)用數(shù)組名,都會退化成指向數(shù)組首地址的指針
再深入的話,就是要了解指針的sizeof
- 指針是用來記錄另一個對象的地址,所以指針的內(nèi)存大小就等于計算機內(nèi)部地址總線的寬度。
- 對一個地址來取大小呢,如果是32位系統(tǒng)的話即為4,如果是64位系統(tǒng)的話為8,所以呢,在函數(shù)中sizeof獲取的是指針的長度而不是數(shù)組的長度
- 指針變量的sizeof值與指針所指的對象沒有任何關(guān)系。
結(jié)論
也就是說在c語言中,數(shù)組名在函數(shù)的調(diào)用中退化成了一個指針,對函數(shù)的參數(shù)使用Sizeof,sizeof獲取的結(jié)果就是指針的大小,而不是數(shù)組本身的大小
再了解一下Sizeof的處理時間
sizeof是C語言的一種單目操作符(但有人也不這么以為,認為它是一種特殊的宏),如C語言的其他操作符++、–等一樣。它并不是函數(shù)。
sizeof操作符以字節(jié)形式給出了其操作數(shù)的存儲大小。操作數(shù)可以是一個表達式或括在括號內(nèi)的類型名。操作數(shù)的存儲大小由操作數(shù)的類型決定,簡單的說其作用就是返回一個對象或者類型所占的內(nèi)存字節(jié)數(shù)。
也就是說,Sizeof是一個C語言的操作符,那么他的處理階段在編譯階段,也就是說你程序沒有運行前,sizeof(arr)就被替換成了一個固定的常量,那么對于動態(tài)生成的數(shù)組大小是不能用sizeof來算出來的。
解決方法
在函數(shù)中多加一個參數(shù),表示數(shù)組的長度
#include <stdio.h> int Number[10]; void print_1(int n[], int len) { printf("數(shù)組大小為:%d\n",len); printf("數(shù)組共有%d個數(shù)據(jù)\n",len/sizeof(int)); } int main() { print_1(Number,sizeof(Number)); return 0; }
以上就是問題的總結(jié)。僅為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
C語言結(jié)構(gòu)體,枚舉,聯(lián)合體詳解
下面小編就為大家?guī)硪黄媪私釩語言結(jié)構(gòu)體,枚舉,聯(lián)合體。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2021-09-09關(guān)于VS2022不能使用<bits/stdc++.h>的解決方案(萬能頭文件)
#include<bits/stdc++.h>包含了目前 C++ 所包含的所有頭文件,又稱萬能頭文件,那么如何在VS2022中使用萬能頭呢?下面小編給大家代理了關(guān)于VS2022不能使用<bits/stdc++.h>的解決方案(萬能頭文件),感興趣的朋友一起看看吧2022-03-03