数组与字符串长度—C语⾔经典⽅法
阅读提⽰:⽂章⽐较冗长,若为了快速做题,请⽤常规⽅法sizeof和⽅法六计数器即可,其他对完成作业都没什么特别的意义,最后感谢您的点击与阅读~
⽂章⽬录
数组与字符串
在C语⾔中,最精彩的地⽅果然还是属于数组与指针。所以写了⼀下在C/C++中,有关于求取数组与字符串长度的⼏种主流的⽅法。写得⽐较简略,若有疑问可以评论出来,若有不⾜欢迎指出,谢谢。
1 数组
静态数组:TYPE Array[NUM];
⽽动态数组:TYPE *Array = (TYPE *) malloc ( sizeof(TYPE) * NUM);
1.1 静态数组
对于任何数组⽽⾔,若长度已知,那么再写个求长度的函数是没有意义的,除⾮求有效长度,⽽⾮分配
长度。⽐如,int array[N]这种形式。⽽且,由于静态数组通常在预编译的时候就知道了数组长度,所以通常没必要在程序运⾏时再计算⼀遍长度,如int array[]。
当然,这种知道是机器知道,⽽不是⼈知道。如果⼈希望知道这个数组的长度⼤⼩,那么这时使⽤在程序预编译阶段求值的运算符、模板等东西就特别合适,尽管它们会有些缺陷。
(1)sizeof 运算符
sizeof运算符可以返回⼀个变量或者类型所占的内存字节数。那么使⽤sizeof,分别获取数组内存和单个元素内存,其值之⽐就是数组长度。
sizeof - 常规⽅法
int array[]={1,2,3,4,5,6,7,8,9}
int elementCount =sizeof(array)/sizeof(array[0]);
以下这⼏种写法是等价的:
1、整个数组所占字节数:sizeof(array) = sizeof(int[9])
2、单个元素所占字节数:sizeof(int) = sizeof(array[0]) = sizeof(array[9]) = sizeof(*array)
3、数组长度 = 整个数组所占字节数 / 单个元素所占字节数
不过,我们在C语⾔中习惯上在使⽤时都把它定义成⼀个宏:
sizeof - 宏定义表达式
/*⽅法⼀:在C语⾔中,sizeof的宏定义*/
#include<stdio.h>
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
int main(void)
{
int array[]={1,2,3};
printf("\nThe length of the array is %lu .\n",ARRAY_SIZE(array));
return0;
}
sizeof - 宏定义函数体
/*⽅法⼆:在C语⾔中,sizeof宏定义的另外⼀种写法*/
#include<stdio.h>
#define GET_ARRAY_LEN(arr, len) {len = (sizeof(arr) / sizeof(arr[0]));}
int main(void)
{
int length =0;
int array[]={1,2,3};
GET_ARRAY_LEN(array, length);
printf("\nThe length of the array is %d .\n", length);
return0;
}
sizeof - Linux内核源码
由于上⾯的宏并不完整,缺少了传参的类型判断容易被误⽤,⽐如⽤在指针⽽不是数组上。那么,在Linux内核源码分析⾥,增加了⼀个判断是否为数组的操作。
//以下⽅法均可运⾏,欢迎尝试
/*⽅法⼀的延伸:在Kennel中,ARRAY_SIZE宏的标准写法,增加了变量类型判断*/
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
/*除此之外,还有另⼀种标准写法*/
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) \
+ sizeof(typeof(int[1 - 2*!!__builtin_types_compatible_p(typeof(arr), typeof(&arr[0]))]))*0)
/*当然,如果上述⽅法太长,可以利⽤typeof来判断类型*/
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof( ((typeof(arr)){})[0]))
关于sizeof的缺点:
c语言如何创建字符串数组1、不能封装成函数
其实这⾥不是sizeof的问题,⽽是数组在作为函数参数传递时,会退化为指针导致实参的信息丢失了,从⽽计算出错。函数只是传递⼀个数组⾸字节的地址,并没有传递其⼤⼩信息。原因很简单,C语⾔的参数都是值传递,如果数组很⼤会浪费许多不必要的空间,所以将数组转换成指针才是⼀个不错的
选择。
所以如果是char型数组,可以利⽤‘\0’来作为边界计算。但对于其他数组,解决⽅法有⼆,要么选择引⽤数组与模板保存实参信息,要么传参时直接带上数组长度信息。
/*错误⽰范!*/
int ARRAY_SIZE(int arr[])//此处数组退化为指针
{
return sizeof(arr)/sizeof((arr)[0]);//爆出警⽰信息
}
2、⽆法求取有效长度
如果在定义数组时就给定了数组的⼤⼩。这样不管数组是增加还是减少元素,sizeof(a)/sizeof(a[0]) 都能⾃动求出数组的长度。需要注意的是,它求出的是数组的总长度,⽽不是数组中存放有意义数据的
个数。
3、不能求取动态数组
⾸先,sizeof是运算符,不是函数。其次,sizeof不需要引⽤任何头⽂件就能够运⾏,它可以在程序预编译阶段就计算出值。所以,像sizeof这种在编译器间静态求值的,是不能在程序运⾏时求出动态改变内存的数组长度。
(2)template 模版
当数组退化为指针时,sizeof不能正确计算出结果,即使选择数组引⽤(&array)来防⽌其变为指针,但这也是不⾏的。这时应该选择数组引⽤+模板,这是因为模板会进⾏类型检查,能识别出来传参出错。
template - 模版函数
/
*⽅法三:在C++中,使⽤模板技术定义⼀个sizeof的函数*/
#include<iostream>
//using namespace std;
template<class T>
int getArrayLen(T& array){
return(sizeof(array)/sizeof(array[0]));
}
int main(int argc,const char* argv[]){
int array[]={1,2,3};
std::cout <<getArrayLen(array)<< std::endl;
return0;
}
template - 函数模版
同样采⽤数组引⽤的⽅法,实现参数的⾃动推断,可以区分数组和指针。函数模版能在编译期获得数组的⼤⼩,并且如果参数是指针则会在编译期间报错。
/*⽅法四:在C++中,使⽤函数模版的参数⾃动推断*/
#include<iostream>
template<typename T, size_t N>
inline size_t countof( T (&array)[N]){
return N;
}
int main(int argc,const char* argv[]){
int array[]={1,2,3};
std::cout <<countof(array)<< std::endl;
return0;
}
template - 预定义宏
在<stdlib.h>头⽂件⾥的_countof宏,则结合了以上两种模版⽅法,利⽤了C++特性进⾏编译推导,。
// From stdlib.h,运⾏失败,还在原因
#if !defined(_countof)
#if !defined(__cplusplus)
#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
#else
extern"C++"
{
template<typename _CountofType, size_t _SizeOfArray>
char(*__countof_helper(UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray];
#define _countof(_Array) sizeof(*__countof_helper(_Array))
}
#endif
#endif
// From Google Chrome,运⾏成功
template<typename T, size_t N>
char(&ArraySizeHelper(T (&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
(3)std::begin 和 std::end
为了统⼀代码并让数组⽀持迭代器,C++11提供了两个新模版函数std::begin、std::end,这两个模版函数可以作⽤于容器和数组。其中,begin()返回指向数组⾸元素的指针,end()返回指向尾元素的下⼀位置的指针,相减就能求出数组长度。
C++迭代器库模板
/*⽅法五:在C++中,使⽤STL库中的迭代器模板函数*/
#include<iostream>
int main(int argc,const int* argv[]){
int arr[]={'1','2','3'};
std::cout << std::end(arr)- std::begin(arr)<< std::endl;
return0;
}
以上所有⽅法,均是在静态编译期间利⽤内存⼤⼩计算出长度,所以若遇到含’\0’的字符数组时,记得需要 length-1。
1.2 动态数组
对于动态数组长度,其⼀般是拿指针变量去遍历,主要使⽤计数器⽅法,采⽤累加得出数组长度。换⽽⾔之,动态数组⼀般由循环迭代⽣成,那么长度也由循环去迭代计算。
不好意思还没写代码, p = (int*)malloc(sizeof(int) * 10);
2 字符串
字符型数组:char str[ ] ;
字节型数组:byte str[ ] ; (其含义是 unsigned char str[ ] ; )
字符串:String str ; (其含义是 const char *str ; )
2.1 Char型数组
字符数组(char型)与其他类型数组不同的是,它有ASCII码为0的结束符’\0’。利⽤这点,在求取字符型数组时,除了可以⽤所有前⾯写的那些⽅法之外,我们还有以下⽅法可以求取。
(1)创建计数器
在C语⾔中,字符串总是由\0字符结束。所以,在声明存储字符串的数组时,其⼤⼩⾄少要⽐所存储的字符数多1,因为编译器通常会⾃动在字符串常量的末尾添加\0。
那么根据这种特性,可创建变量作为计数器,然后在while循环中不断地递增,直到到达字符串尾为⽌。当循环结束时,这个计数器变量的值,就包括了字符串的字符个数,但不包含终⽌字符。
count计数器
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论