当前位置: 代码迷 >> 综合 >> C语言笔记(十七)——sizeof()、strlen()与str.length()
  详细解决方案

C语言笔记(十七)——sizeof()、strlen()与str.length()

热度:19   发布时间:2023-11-23 21:46:31.0

sizeof和strlen的用法和区别:

  • sizeof不等同于strlen

         ——p为局部数组变量时,sizeof(p)为数组的字节长度;

         ——p为指针参数传参时,sizeof(p)为指针的字节长度——4;

  • strlen只能用char*类型做参数,且必须以'\0'结尾,strlen将返回它的长度,但不包括'\0'.

求数组长度:

1、sizeof()关键字:

根据sizeof ()关键字可以获得参数(数组、指针、数据类型、对象或者函数)在内存中所占的字节数,所以数组所占总的字节数除以一个元素所占的字节数就是数组的长度。如下代码所示,数组 a 是 int 型的,每个元素占 4 字节,所以长度为 10 的数组在内存中所占的字节数就是 40。而总的字节数除以一个元素所占的字节数就是数组的长度,如下面这个程序:

# include <stdio.h>
int main()
{   int a[10] = {0, 3, 5, 6, 9};int cnt = sizeof(a) / sizeof(int);printf("cnt = %d\n", cnt);return 0;
}

运行结果:

注意1:在给出数组大小后,sizeof出的是数组的总长度,而不是数组中存放的有意义的数据的个数

可以采用不给数组大小的方法来避免这个问题,比如下例中的数组b:

# include <stdio.h>
int main()
{   int a[10] = {0, 3, 5, 6, 9};int b[] = {1,3,5,4};int cnt = sizeof(a) / sizeof(int);int cnt1 = sizeof(b) / sizeof(int);printf("cnt = %d, cnt1 = %d\n", cnt, cnt1);return 0;
}

注意2在函数调用数组时,除了传递数组名参数外,还要传递数组长度

因为sizeof()是编译器在编译的时候计算的,无法动态计算。而p是函数参数,到了suzu函数中,p只是一个指针地址(系统在本函数运行时,是不知道p所表示的地址有多大的数据存储空间,这里只是告诉函数:一个数据存储空间首地址),所以,sizoef(p)的结果是指针变量p占内存的大小,一般在32位机上是4个字节。p[]是int类型,有4个字节,sizeof(p)也是4个字节,所以,len的结果永远是1。

void suzu(int p[])
{int len = sizeof(p) / sizeof(int);printf("function_len = %d\n", len);//显示函数里的数组长度for (int i = 0; i < len; i++){printf("%d|", p[i]);} printf("\n");
}int main()
{int a[] = { 1, 3, 5, 3, 4, 6 };int length = sizeof(a) / sizeof(int);printf("main_len = %d\n", length);suzu(a);system("pause");return 0;
}

对于指针(int *)或者将数组传递给函数时,无法使用sizeof获取数组大小的,即使在函数声明中写int[]也不行。应该在形参中再传递数组或者字符串的“长度”参数,因为函数内部无法得到数组的长度。代码如下:

void print(int *p, int length)
{for (int i = 0; i < length; i++){printf("%d|", p[i]);}printf("\n");
}int main()
{int a[] = { 1, 3, 5, 3, 4, 6 };int length = sizeof(a) / sizeof(int); //数组长度print(a, length); //函数中加了长度参数system("pause");return 0;
}

结果

2、strlen()函数

自动计算字符串中字符的个数,遇到‘\0’就结束计算

使用该函数时:

  1. 参数必须是字符型指针(char*),且必须是以‘\0’结尾的。
  2. 数组名作为参数传入时,实际上数组就退化成指针了。由于strlen只能接受char*类型,所以编译时出错,或者输出char类型的字节数1。
int main()
{int b[] = { 2, 3, 5, 4 };char* d = "asdfsds";int cnt = sizeof(b) / sizeof(b[0]);int cnt1 = strlen(b); //数组做参数时,实际传入了char类型的指针,故输出cnt1的长度为1printf("cnt = %d, cnt1 = %d\n", cnt, cnt1);int cnt2 = sizeof(d) / sizeof(d[0]);//将'\0'也当成了一个字符进行计算了int cnt3 = strlen(d);printf("cnt2 = %d, cnt3 = %d\n", cnt2, cnt3);system("pause");return 0;
}

结果:

注意:

  • strlen()函数可以求出字符数组中字符串的有效长度,即不包含字符串末尾结束符‘\0’
  • sizeof()操作符求出的字符串的长度包含字符串末尾的结束符 ‘\0’
  • 当在函数内部使用sizeof()求解由函数的形参传入的数组的长度时,得到的结果指针的长度,即对应char类型的字节数,而不是字符串的长度,此处一定要小心;
  • strlen()这种方法有个缺陷,因为其依赖‘\0’判断字符串是否结束。所以,恶意攻击者会构造一个不包含‘\0’的字符串,然后让数据写入数组之外的程序内存空间,从而进行破坏;为避免这个问题,在进行字符串的插入剪切、复制等操作时,一般都选可以控制复制字符数量的函数,比如:
  • 字符串复制:strcpy -> strncpy
  • 字符串连接:strcat  -> strncat

strcpy只是复制字符串,但不限制复制的数量,很容易造成缓冲溢出。strncpy要安全一些。

strncpy能够选择一段字符输出,strcpy则不能。它们的具体说明如下:

字符串复制 函数 char* strcpy(char *s2, const char *s1); char* strncpy(char *s2, const char *s1, size_t n); void  *memcpy(void *s1,  const void *s2,  size_t  n);
说明 把s1指向的串(包括空字符)复制到s2指向的数组中。返回s2的值 从s1指向的数组中最多复制n个字符(不复制空字符后面的字符)到s2指向的数组中。返回s2的值 从s2指向的对象中复制n个字符到s1指向的对象中。返回s1的值。
  strcpy 是依据 “\0” 作为结束判断的,如果 s2 的空间不够,则会引起 buffer overflow。

Strncpy和memcpy很相似,只不过它在一个终止的空字符处停止。当n>strlen(s1)时,给s2不够数的空间里填充“\0”;当n<=strlen(s1)时,s2是没有结束符“\0”的。

这里隐藏了一个事实,就是s2指向的内存一定会被写n个字符。

memcpy用来在内存中复制数据,由于字符串是以“\0”结尾的,所以对于在数据中包含“\0”的数据只能用memcpy,如:"hell\0oworld"。

所以总的来说注意:

  1. s2指向的空间要足够拷贝;使用strcpy时,s2指向的空间要大于等于s1指向的空间;使用strncpy或memcpy时,s2指向的空间要大于或等于n。
  2. 使用strncpy或memcpy时,n应该大于strlen(s1),或者说最好n >= strlen(s1)+1;这个1 就是最后的“\0”。
  3. 使用strncpy时,确保s2的最后一个字符是“\0”。

比如:

char name[]="Chinanet",dest[20]={0};strncpy(dest,name,9);printf("%s\n",dest);strncpy可实现strcpy的字符串复制:char name[]="Chinanet",dest[20]={0};strncpy(dest,name,sizeof(name));printf("%s\n",dest);

二、求字符串长度

1.strlen()函数   使用范围C/C++

其参数必须是char*类型

char* ch = "sdffffsfsd";

scanf("%d\n",strlen(ch));

2.length()函数   只能用在C++中

需要引用string头文件。str.length()是string类对像str调用的成员函数

#include <string>

string str = "sfsjflkf"; //字符串类型

cout << str.length() << endl;

3.size()函数   只能用在C++中

#include <string>

string str = "sfsjflkf"; //字符串类型

cout << str.size() << endl;

此外,size()函数还可以获取vector类型的长度,例如:

vector < int> num(15,2) ;  //表示初始化15个元素,每个元素都是2

则:

num.size() = 15。

参考:

教程:https://www.bilibili.com/video/av84476631?p=6

strcpy、strncpy与memcpy的区别与使用方法

  相关解决方案