Chinaunix首页 | 论坛 | 博客
  • 博客访问: 75230
  • 博文数量: 22
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 134
  • 用 户 组: 普通用户
  • 注册时间: 2015-04-27 22:31
个人简介

梦想是要有的,万一实现了呢!

文章分类

全部博文(22)

文章存档

2015年(22)

分类: C/C++

2015-05-06 09:42:01

strlen与sizeof的区别
  1.从功能定义上,strlen函数,用来求字符串的长度,sizeof函数是用来求指定变量或变量类型等所占用内
存的大小,单位是字节;
  2.sizeof是运算符,而strlen是C库函数,strlen只能用   char*做参数,且以'/0'结尾的 !
  对于静态数组处理:
     char str[20]="0123456789";
     strlen(str)=10;   //表示数组中字符串的长度
     sizeof(str)=20;   //表示数组变量分配的长度
  对于指针处理:
     char *str="0123456789";
     strlen(str)=10;     //表示字符串的长度
     sizeof(str)=4;      //表示指针变量的所占内存大小
     sizeof(*str)=1;     //表示'0'这个字符变量的所占内存大小

*********************************************************************************************


实验一 (32bit)
---------------------------------------------------------------------------------------
#include
#include
#include
int main()
{
        char ch = 'A';
        int num = 12;
        char * str1 = "hello";
        char * str2 = "hello\0";
        char * str3 = "hello\\0";
        printf("ch addr is %p\n",&ch);
        printf("ch is %c\n",ch);
        printf("num addr -s %p\n",&num);
        printf("num is %d\n",num);
        printf("--------------------------------\n");
        printf("str1 addr is %p\n",&str1);
        printf("str1 is %s\n",str1);
        printf("strlen str1 is %d\n",strlen(str1));
        printf("sizeof str1 is %d\n",sizeof(str1));
        printf("--------------------------------\n");
        printf("str2 addr is %p\n",&str2);
        printf("str2 is %s\n",str2);
        printf("strlen str2 is %d\n",strlen(str2));
        printf("sizeof str2 is %d\n",sizeof(str2));
        printf("--------------------------------\n");
        printf("str3 addr is %p\n",&str3);
        printf("str3 is %s\n",str3);
        printf("strlen str3 is %d\n",strlen(str3));
        printf("sizeof str3 is %d\n",sizeof(str3));
        printf("--------------------------------\n");
        return 0;
}


结果:
[root@Gypsy_111 test]# gcc str.c -o str
[root@Gypsy_111 test]# ll
总用量 12
-rwxr-xr-x 1 root root 5577 5月   5 11:08 str
-rw-r--r-- 1 root root  969 5月   5 11:08 str.c
[root@Gypsy_111 test]# ./str
ch addr is 0xbf84feef
ch is A
num addr -s 0xbf84fee8
num is 12
--------------------------------
str1 addr is 0xbf84fee4
str1 is hello
strlen str1 is 5
sizeof str1 is 4
--------------------------------
str2 addr is 0xbf84fee0
str2 is hello
strlen str2 is 5
sizeof str2 is 4
--------------------------------
str3 addr is 0xbf84fedc
str3 is hello\0
strlen str3 is 7
sizeof str3 is 4
--------------------------------
[root@Gypsy_111 test]#
---------------------------------------------------------------------------------------


结论:
1、如下两种情况,
char * str1 = "hello";
char * str2 = "hello\0";
打印出的结果一致,说明这样声明字符串的时候,如果自己不手动添加 '\0' 结束符,
那么系统也会自动在末尾给添加 '\0' 结束符
2、关于栈的地址分配:
栈是向 低地址 扩展的数据结构,是一块连续的内存区域。
这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的
3、指针类型在 32bit 机上是占4个字节的。


实验二 (32bit)
---------------------------------------------------------------------------------------
#include
#include
#include
int main()
{
        char * str1 = "hello";
        char * str2 = "UNIX\0";
        printf("--------------------------------\n");
        printf("str1 addr is %p\n",&str1);
        printf("str1 is %s\n",str1);
        printf("strlen str1 is %d\n",strlen(str1));
        printf("sizeof str1 is %d\n",sizeof(str1));
        printf("--------------------------------\n");
        printf("str2 addr is %p\n",&str2);
        printf("str2 is %s\n",str2);
        printf("strlen str2 is %d\n",strlen(str2));
        printf("sizeof str2 is %d\n",sizeof(str2));
        printf("--------------------------------\n");
        printf("find the hello addr which stored in str1: %p\n",str1);
        printf("Analysis 0: %c\n",*str1);
        printf("Analysis 1: %c\n",*str1+1);
        printf("Analysis 2: %c\n",*str1+2);
        printf("Analysis 3: %c\n",*(str1+3));
        printf("Analysis 4: %c\n",*(str1+4));
        printf("Analysis 5: %c\n",*(str1+5));
        printf("Analysis 6: %c\n",*(str1+6));
        printf("--------------------------------\n");
        printf("find the UNIX addr which stored in str2: %p\n",str2);
        printf("Analysis 0: %c\n",*str2);
        printf("Analysis 1: %c\n",*str2+1);
        printf("Analysis 2: %c\n",*str2+2);
        printf("Analysis 3: %c\n",*(str2+3));
        printf("Analysis 4: %c\n",*(str2+4));
        return 0;
}


结果:
[root@Gypsy_111 test]# gcc str.c -o str
[root@Gypsy_111 test]# ./str
--------------------------------
str1 addr is 0xbf9a5a0c
str1 is hello
strlen str1 is 5
sizeof str1 is 4
--------------------------------
str2 addr is 0xbf9a5a08
str2 is UNIX
strlen str2 is 4
sizeof str2 is 4
--------------------------------
find the hello addr which stored in str1: 0x8048784
Analysis 0: h
Analysis 1: i
Analysis 2: j
Analysis 3: l
Analysis 4: o
Analysis 5:
Analysis 6: U
--------------------------------
find the UNIX addr which stored in str2: 0x804878a
Analysis 0: U
Analysis 1: V
Analysis 2: W
Analysis 3: X
Analysis 4:
[root@Gypsy_111 test]#
---------------------------------------------------------------------------------------


结论:
1、针对:char * str1 = "hello";
      char * str2 = "UNIX\0";
采用对字符串指针解引用的时候:
输出的时候需要  printf("Analysis 0: %c\n",*str1);    
注意一定是  '%c' 而不是 '%s' !

2、指针变量str1所存储的值,也就是 "hello" 这个字符串的真实内存地址。
printf("find the hello addr which stored in str1: %p\n",str1);
find the hello addr which stored in str1: 0x8048784
printf("find the UNIX addr which stored in str2: %p\n",str2);
find the UNIX addr which stored in str2: 0x804878a

3、这里需要解释下不同的地址分配问题:
对于  char * str1 = "hello"  这句
hello 是字符串常量,存储在 "文字常量区"
而 str1 则存储在栈中,所以在分别查看其内存地址的时候会发现地址差别很大。

*str1      --->  表示字符串的第一个字符 即 'h'
*str1+1    --->  表示取出第一个字符串(即 'h'),并加 1 ('h' 对应ASCII码值加1)即 'i'
*(str1+4)  --->  表示取出指针变量str1所指向的地址往后数4位所对应的那个字符

两个指针变量的内存地址分别为:
str1  --->  0xbf9a5a0c
str2  --->  0xbf9a5a08

存储的大致结构如下:
---------------------------
h|e|l|l|o|\0|U|N|I|X\0|....
---------------------------
地址分配如下:
h   ---> 0x8048784 
e   ---> 0x8048785
l   ---> 0x8048786
l   ---> 0x8048787
o   ---> 0x8048788
\0  ---> 0x8048789
U   ---> 0x804878a
N   ---> 0x804878b
I   ---> 0x804878c
X   ---> 0x804878d
\0  ---> 0x804878e
...


这也就解释了 为什么 *(str1+6) 会得到 U
printf("Analysis 6: %c\n",*(str1+6));
Analysis 6: U


输出的结果中:
-------------------
Analysis 4: o
Analysis 5:       
Analysis 6: U
-------------------
Analysis 5:   对应的就是系统给 "hello" 默认添加的 '\0'


实验三 (32bit)
---------------------------------------------------------------------------------------
#include
#include
int main()
{
        char * str1 = "UNIX";
        char str2[] = {'n','i','h'};
        char * str3 = "FreeBSD";
        printf("str1 addr is %p\n",&str1);
        printf("the string addr stored str1 is %p\n",str1);
        printf("str2 addr is %p\n",&str2);
        printf("the string addr stored str2 is %p\n",str2);
        printf("str3 addr is %p\n",&str3);
        printf("the string addr stored str3 is %p\n",str3);
        printf("str1 is %s\n",str1);
        printf("str2 is %s\n",str2);
        printf("str3 is %s\n",str3);
        printf("str2.1 is %c\n",*str2);
        printf("str2.2 is %c\n",*(str2+1));
        printf("str2.3 is %c\n",*(str2+2));
        printf("str2.4 is %c\n",*(str2+3));
        printf("str2.5 is %c\n",*(str2+5));
        printf("str2.6 is %c\n",*(str2+6));
        printf("str2.7 is %c\n",*(str2+7));
        printf("strlen str1 is %d\n",strlen(str1));
        printf("sizeof str1 is %d\n",sizeof(str1));
        printf("strlen str2 is %d\n",strlen(str2));
        printf("sizeof str2 is %d\n",sizeof(str2));
        printf("strlen str3 is %d\n",strlen(str3));
        printf("sizeof str3 is %d\n",sizeof(str3));
        return 0;
}


结果:
str1 addr is 0xbfc0500c
the string addr stored str1 is 0x8048714
str2 addr is 0xbfc05009
the string addr stored str2 is 0xbfc05009
str3 addr is 0xbfc05004
the string addr stored str3 is 0x8048719
str1 is UNIX
str2 is nih`?
str3 is FreeBSD
str2.1 is n
str2.2 is i
str2.3 is h
str2.4 is
str2.5 is
str2.6 is
str2.7 is `
strlen str1 is 4
sizeof str1 is 4
strlen str2 is 11
sizeof str2 is 3
strlen str3 is 7
sizeof str3 is 4
---------------------------------------------------------------------------------------
在这个实验中,
char * str1 = "UNIX"; 
char str2[] = {'n','i','h'};
char * str3 = "FreeBSD";
这三者的 内存地址分别是:
str1   --->   0xbfc0500c
str2   --->   0xbfc05009
str3   --->   0xbfc05004


字符串的内存地址:
"UNIX"       存储在  0x8048714
"FreeBSD"    存储在  0x8048719


{'n','i','h'};       0xbfc05009
很明显看不它和上面的地址格式不同,是因为 {'n','i','h'} 很明显是字符数组,存储在栈中
而前两者是常量字符串,存储在 文字常量区!
所以
printf("str2 addr is %p\n",&str2);
printf("the string addr stored str2 is %p\n",str2);
所以,这两句求出的是同一个地址。


对于 char str2[] = {'n','i','h'}; 这种形式的赋值,系统把它视为字符数组
所以 ,系统也没有默认给他添加 结束符'\0' 
从而在 printf("str2 is %s\n",str2); 执行这句话时系统找不到 结束符
所以会得到:
str2 is nih`?


同样的
printf("strlen str2 is %d\n",strlen(str2));
printf("sizeof str2 is %d\n",sizeof(str2));


strlen str2 is 11   ---->  这是不准的
sizeof str2 is 3


实验四 (32bit)
---------------------------------------------------------------------------------------
#include
#include
#include
#include
int main()
{
        char * str1 = (char*)malloc(10*sizeof(char));
        char * str2 = (char*)malloc(3*sizeof(char));
        char * str3 = (char*)malloc(5*sizeof(char));
        if(str1==NULL || str2 == NULL || str3 == NULL)
        {
                printf("Not Enough Memory!\n");
        }
        else
        {
                strcpy(str1,"Hi,Linux");
                strcpy(str2,"AB");
                strcpy(str3,"WORLD");
                printf("--------------------------------\n");
                printf("str1 addr is %p\n",&str1);
                printf("str2 addr is %p\n",&str2);
                printf("str3 addr is %p\n",&str3);
                printf("--------------------------------\n");
                printf("strlen str1 is %d\n",strlen(str1));
                printf("sizeof str1 is %d\n",sizeof(str1));
                printf("strlen str2 is %d\n",strlen(str2));
                printf("sizeof str2 is %d\n",sizeof(str2));
                printf("strlen str3 is %d\n",strlen(str3));
                printf("sizeof str3 is %d\n",sizeof(str3));
                printf("--------------------------------\n");
                printf("malloc to str1 is %p\n",str1);
                printf("malloc to str2 is %p\n",str2);
                printf("malloc to str3 is %p\n",str3);
                printf("--------------------------------\n");
        }
        free(str1);
        free(str2);
        free(str3);
        return 0;
}


结果:
[root@Gypsy_111 test]# ./str
--------------------------------
str1 addr is 0xbfbb3c5c
str2 addr is 0xbfbb3c58
str3 addr is 0xbfbb3c54
--------------------------------
strlen str1 is 8
sizeof str1 is 4
strlen str2 is 2
sizeof str2 is 4
strlen str3 is 5
sizeof str3 is 4
--------------------------------
malloc to str1 is 0x8a6c008
malloc to str2 is 0x8a6c018
malloc to str3 is 0x8a6c028
--------------------------------
---------------------------------------------------------------------------------------


1、C 语言里面怎么给一个用malloc申请的动态空间赋值
比如说 int p;
p=(int *)malloc(sizeof(int)*n);
那么p就相当于数组p[n]的基地址了,所以对它赋值只要用数组的写法:
p[i]=x;就可以了;
也可以采用 strcpy(str1,"Hi,Linux"); 这种形式赋值。


2、先后声明了三个指针变量:
char * str1 = (char*)malloc(10*sizeof(char));
char * str2 = (char*)malloc(3*sizeof(char));
char * str3 = (char*)malloc(5*sizeof(char));
可以看到用malloc申请到的地址空间:
malloc to str1 is 0x8a6c008
malloc to str2 is 0x8a6c018
malloc to str3 is 0x8a6c028
用malloc动态申请的地址空间是存储在堆区的,而且和栈相反,是向高地址扩展的。
而且实际分配的内存大小大于等于 用户所申请的大小,
关于malloc实际分配的大小很复杂,稍后再深入研究。


实验五 (32bit)
---------------------------------------------------------------------------------------
#include
#include
#include
int main()
{
    int a = 2;
    char str1[]="Unix";
    char ch = 'A';
    char str2[]={'n','i','h'};
    printf("strlen str1 is %d\n",strlen(str1));
    printf("sizeof str1 is %d\n",sizeof(str1));
    printf("strlen str2 is %d\n",strlen(str2));
    printf("sizeof str2 is %d\n",sizeof(str2));
    printf("-----------------------------------------\n");
    printf("a is %d\n",a);
    printf("str1 is %s\n",str1);
    printf("ch is %c\n",ch);
    printf("str2 is %s\n",str2);
    printf("-----------------------------------------\n");
    printf("a addr is %p\n",&a);
    printf("str1 addr is %p\n",str1);
    printf("ch addr is %p\n",&ch);
    printf("str2 addr is %p\n",str2);
    printf("%c\n",str2[4]);
    printf("%c\n",str2[5]);
    printf("%c\n",str2[6]);
    printf("%c\n",str2[7]);
    return 0;
}


结果:
[root@Gypsy_111 test]# ./men
strlen str1 is 4
sizeof str1 is 5
strlen str2 is 8
sizeof str2 is 3
-----------------------------------------
a is 2
str1 is Unix
ch is A
str2 is nihAUnix
-----------------------------------------
a addr is 0xbfb6455c
str1 addr is 0xbfb64557
ch addr is 0xbfb64556
str2 addr is 0xbfb64553
U
n
i
x
---------------------------------------------------------------------------------------


从这里也可以看出:a str1[] ch str2[]  这些变量都是在栈中分配的内存
而且从地址上可以看出都是连续的,期间差距也是符合相应变量类型的大小
a addr is 0xbfb6455c
str1 addr is 0xbfb64557
ch addr is 0xbfb64556
str2 addr is 0xbfb64553


对于 char str2[]={'n','i','h'} ,由于缺少终结符,
所以执行 printf("str2 addr is %p\n",str2); 这句话时,指针会一直往后读取,
直到遇到了 char str1[]="Unix"; 所以会有如下结果:
str2 is nihAUnix


需要注意的是:
对于这两个数组:
char str1[]="Unix";
char str2[]={'n','i','h'};


**********************************************************
是无法求出str1和str2的实际内存地址的,这一点很重要!!!
**********************************************************


printf("str1 addr is %p\n",str1); 
printf("str2 addr is %p\n",str2);

printf("str1 addr is %p\n",str1); 
printf("str2 addr is %p\n",str2);
这两者的输出是一样的,但都是该数组所存储的首字符的内存地址,而不是数组的地址


有这种情况:
char str1[]="Unix";
char * str3 = "world!";


虽然右侧都是字符串常量,但二者存储的位置完全不同,具体取决于左侧的类型
Unix    被视为数组存储在栈区;
world!  被视为字符串常量存储在 文字常量区
见结果:
-----------------------------------------------------
printf("str1 addr is %p\n",&str1);
printf("str1 addr is %p\n",str1);
printf("str3 addr is %p\n",&str3);
printf("str3 addr is %p\n",str3);


str1 addr is 0xbfb81a37
str1 addr is 0xbfb81a37
str3 addr is 0xbfb81a2c
str3 addr is 0x8048714
-----------------------------------------------------



实验六 
---------------------------------------------------------------------------------------


#include
#include
#include
int main()
{
    int num1 = 10;
    char chh = 'B';
    char str1[]="Unix";
    char ch = 'A';
    int num2 = 5;
    char str2[]={'n','i','h'};
    char * str3 = "123456789";
    printf("-----------------------------------------\n");
    printf("num1 is %d\n",num1);
    printf("ch is %c\n",ch);
    printf("str1 is %s\n",str1);
    printf("ch is %c\n",ch);
    printf("num2 is %d\n",num2);
    printf("str2 is %s\n",str2);
    printf("str3 is %s\n",str3);
    printf("-----------------------------------------\n");
    printf("num1 addr is %p\n",&num1);
    printf("chh addr is %p\n",&chh);
    printf("str1 addr is %p\n",&str1);
    printf("ch addr is %p\n",&ch);
    printf("num2 addr is %p\n",&num2);
    printf("str2 addr is %p\n",&str2);
    printf("str3 addr is %p\n",&str3);
    printf("-----------------------------------------\n");
    return 0;
}


在32bit上的结果:
[root@Gypsy_111 test]# ./men
-----------------------------------------
num1 is 10
ch is A
str1 is Unix
ch is A
num2 is 5
str2 is nih
str3 is 123456789
-----------------------------------------
num1 addr is 0xbfb0cc1c
chh addr is 0xbfb0cc1b
str1 addr is 0xbfb0cc16
ch addr is 0xbfb0cc15
num2 addr is 0xbfb0cc10
str2 addr is 0xbfb0cc0d
str3 addr is 0xbfb0cc08
-----------------------------------------


在64bit上的结果:
[boxer@Linuxer ~]$ ./men
-----------------------------------------
num1 is 10
ch is A
str1 is Unix
ch is A
num2 is 5
str2 is nih
str3 is 123456789
-----------------------------------------
num1 addr is 0x7fff4643fc0c
chh addr is 0x7fff4643fc0b
str1 addr is 0x7fff4643fc00
ch addr is 0x7fff4643fbff
num2 addr is 0x7fff4643fbf8
str2 addr is 0x7fff4643fbf0
str3 addr is 0x7fff4643fbe8
-----------------------------------------
---------------------------------------------------------------------------------------

关于内存分配涉及到对齐的问题,很麻烦啊。。。

遗留的问题
1、关于malloc实际分配内存的大小如何确定?是否和编译器有关?
2、关于内存分配的对齐问题,到底按什么规则分配的?
笔者小白一个,望读者不吝赐教!


参考的文章:
http://www.cnblogs.com/qlwy/archive/2012/05/23/2514344.html
http://www.cnblogs.com/renxs/archive/2012/01/18/2325352.html
向前辈致敬!


阅读(717) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

hitwh_Gypsy2015-05-06 09:45:09

自己忙活了一整天,给自己点个赞吧