一个关于C的strlen的使用问题

sun68807 2009-01-08 07:03:23
//这个函数有问题,使用malloc为newPath分配内存空间,分配完以后,总是分配33个字节(实际长度小于33的时候)。
/*
* 函数名称:CreateSearchPath(const char *prefix,const char *dirName)
* 函数介绍: 将形如C:\\temp\\*的perfix和代表子目录名subdir的dirName合并成一个文件路径并在最后加上* ,此例中,最后
合并后应该是 C:\\temp\\subdir\\*
* 输入参数: 一个代表路径的字符串,最后一个字符如果是*,就会被去掉。
* 输出参数: 一个子目录的目录名
* 返回值 : 成功返回一个指向dirName文件夹的新的路径,后面加*,失败返回NULL
失败原因:1.指针错误,2.内存不足
*/
char *CreateSearchPath(const char *perfix,const char *dirName)
{
char *newPath = NULL;
int perfixLen;
int suffixLen;
perfixLen = strlen(perfix);
suffixLen = strlen(dirName);
//新的字符串=perfix(如果其末尾有*,则去掉 + suffix(仅仅是文件名) + “\\*”)
if ('*' == perfix[perfixLen-1])//数组从0开始
{
perfixLen--;//去掉*字符
}

/*8*/ newPath = (char *)malloc(sizeof(perfix[0]) * (perfixLen+suffixLen+2));//为什么这里是33???
#ifdef _DEBUG
/*9*/ printf("in function check:%d\t%d\t",perfixLen,suffixLen);
/*10*/ printf("in Funciton check%d\n",strlen(newPath));
#endif // _DEBUG

if (newPath)
{
strncpy(newPath,perfix,perfixLen);
strncpy(newPath+perfixLen,dirName,suffixLen);
strncpy(newPath+perfixLen+suffixLen,"\\*",2);
return newPath;
}
else
{
return NULL;/*Probably out of RAM*/
}
}

1.主要是注意8,9,10行的程序,每次打印出来newPath的值都是33,换另外一个机器,是24。我想问下大家,这里出现这个问题是不是因为我用strlen去量用malloc的来的内存空间,这个是错误的?
2.其次,在主函数中:
int main()
{
char *a = "C:\\temp\\*";
char *b = "subDir";
/*3*/ char *c = CreateSearchPath(a,b);
printf("%s",c);
}
第三行,我得到是一段包含乱码的打印,也就是说程序没有帮我自己加上'\0',我想问下:是不是调用malloc的来的字符串,都要自己去为这个字符串加上'\0'?
...全文
441 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
baiyunhao 2010-04-14
  • 打赏
  • 举报
回复
漂过~~~
wyswyg63 2009-01-08
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 sun68807 的回复:]
1楼的朋友第一个给出回答,而且说的比较清楚,但是第二个问题的回答不够明确,给12分
2楼的回答,我认为你似乎没有读懂我的问题。
[/Quote]
呵呵,我没去看你的代码,直接看你的问题了,对于你的提问,这样回答很正确啊。
我想问下:是不是调用malloc的来的字符串,都要自己去为这个字符串加上'\0'?
1、调用malloc只是分配空间啊,不可能有什么字符串啊,lz对这个函数的功能理解错了。字符串是靠你后面字节写进去的。lz代码里用的是strncpy这个函数写进去的。至于你用什么函数写字符串进去(strcpy/memcpy等等)这个是和malloc没有关系的。
2、既然调用malloc没有什么来的字符串。那么后面那个为这个字符串加上'\0'?就根本不是问题了。
至于你字符串最后没'\0',你看你的函数strncpy(newPath+perfixLen+suffixLen,"\\*",2); 这个只复制2个字符\\过去,后面怎么可能会有'\0',所以当然要自己写进去了。
3、至于你那个打印值都是33,这个问题很多人都回答了。malloc只分配空间,所以一般来说需要手动把malloc分配的空间清0
ptr = (char*)malloc(SIZE);
memset(ptr, '\0', SIZE); //一般最好malloc后都加上这句初始化一下,全部清0, 如果你加了这句前面那个就不用再写'\0'进去了。
sun68807 2009-01-08
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 xidianxiancai 的回复:]
引用楼主 sun68807 的帖子:
//这个函数有问题,使用malloc为newPath分配内存空间,分配完以后,总是分配33个字节(实际长度小于33的时候)。
/*
* 函数名称:CreateSearchPath(const char *prefix,const char *dirName)
* 函数介绍: 将形如C:\\temp\\*的perfix和代表子目录名subdir的dirName合并成一个文件路径并在最后加上* ,此例中,最后
合并后应该是 C:\\temp\\subdir\\*
* 输入参数: 一个代表路径的字符串,…
[/Quote]

1.你得出16,是正常的,因为那个值是一个随机值,不同的机器上有不同的答案。
2.注意你的输出 in function check:8 6 in Function check20
newPath的大小是20?你代码中是分配20给它么?
3.你运行后面没有输出乱码,可能是应为你后面的那段内存刚好是空的,没有其他的数据在里面,而我的机器上,不是空的,因此,有乱码
sun68807 2009-01-08
  • 打赏
  • 举报
回复
1楼的朋友第一个给出回答,而且说的比较清楚,但是第二个问题的回答不够明确,给12分
2楼的回答,我认为你似乎没有读懂我的问题。
7楼的回答最准确,也清楚。给10分
h_5_hao 给的代码不加注释,而且有问题,C必须在函数开头定义变量,给出的资料虽然有用针对性也不强。这些都是酌情给分
8楼朋友给出代码,并且在修改的地方加上了注释。
9楼的朋友也给出了代码,但是有一个小问题。malloc处没有+1,但是考虑到
strcat(newPath, newPath[perfixLen] == '\\' ? "*":"\\*");
这句话写的不错,也给10分吧。
xidianxiancai 2009-01-08
  • 打赏
  • 举报
回复
[Quote=引用楼主 sun68807 的帖子:]
//这个函数有问题,使用malloc为newPath分配内存空间,分配完以后,总是分配33个字节(实际长度小于33的时候)。
/*
* 函数名称:CreateSearchPath(const char *prefix,const char *dirName)
* 函数介绍: 将形如C:\\temp\\*的perfix和代表子目录名subdir的dirName合并成一个文件路径并在最后加上* ,此例中,最后
合并后应该是 C:\\temp\\subdir\\*
* 输入参数: 一个代表路径的字符串,最后一个字符如果是*,就会被…
[/Quote]
首先“//为什么这里是33???”有点不明白,我在vc下运行的结果是16,而不是你说的33,不知道你的33是怎么得来的?
其次 1.主要是注意8,9,10行的程序,每次打印出来newPath的值都是33,换另外一个机器,是24。我想问下大家,这里出现这个问题是不是因为我用strlen去量用malloc的来的内存空间,这个是错误的? 我感觉应该用sizeof去衡量newPath的大小的吧。
最后,我在vc下跑的结果是
in function check:8 6 in Function check20
C:\temp\subDir\* Press any key to continue
没有出来你说的什么乱码?一切都正常的啊!
谢谢!

sun68807 2009-01-08
  • 打赏
  • 举报
回复
谢谢各位的帮助,我已经结贴。给分原则:
答对问题的,都是10分起。
没有答对的,酌情给5分以下。
与大家分享好的资料的,根据资料有用程度和精炼程度给分(1-10)分。
先回帖的,再加(1-5分)。
回答得很漂亮的,再加(1-10)。
yellowhwb 2009-01-08
  • 打赏
  • 举报
回复

char *CreateSearchPath(const char *perfix,const char *dirName)
{
char *newPath = NULL;
int perfixLen;
int suffixLen;
perfixLen = strlen(perfix);
suffixLen = strlen(dirName);
//新的字符串=perfix(如果其末尾有*,则去掉 + suffix(仅仅是文件名) + “\\*”)
if ('*' == perfix[perfixLen-1])//数组从0开始
{
perfixLen--;//去掉*字符
}

newPath = (char *)malloc(perfixLen+suffixLen+2);
#ifdef _DEBUG
printf("in function check:%d\t%d\t",perfixLen,suffixLen);
printf("in Funciton check%d\n",strlen(newPath));
#endif // _DEBUG
if (newPath)
{
memset(newPath, 0, perfixLen+suffixLen+2);
memcpy(newPath, perfix, perfixLen);
strcat(newPath, dirName);
strcat(newPath, newPath[perfixLen] == '\\' ? "*":"\\*");
return newPath;
}
else
{
return NULL;/*Probably out of RAM*/
}
}

void main()
{
char *a = "C:\\temp\\*";
char *b = "subDir";
/*3*/ char *c = CreateSearchPath(a,b);
printf("%s",c);
}

lz试一下:)
xiaoyisnail 2009-01-08
  • 打赏
  • 举报
回复

#include <stdio.h>
#include <string.h>
#include <malloc.h>

char *CreateSearchPath(const char *perfix,const char *dirName)
{
char *newPath = NULL;
int perfixLen;
int suffixLen;
perfixLen = strlen(perfix);
suffixLen = strlen(dirName);

if ('*' == perfix[perfixLen-1])//数组从0开始
{
perfixLen--;//去掉*字符
}

newPath = (char *)malloc(sizeof(perfix[0]) * (perfixLen+suffixLen+3));

if(newPath)
{
strncpy(newPath,perfix,perfixLen);
strncpy(newPath+perfixLen,dirName,suffixLen);
strncpy(newPath+perfixLen+suffixLen,"\\*",2);

newPath[perfixLen+suffixLen+2]='\0';//这里加上

return newPath;
}
else
{
return NULL;/*Probably out of RAM*/
}
}

int main()
{
char *a = "C:\\temp\\*";
char *b = "subDir";
char *c = CreateSearchPath(a,b);
printf("%s",c);

return 0;
}
xiaoyisnail 2009-01-08
  • 打赏
  • 举报
回复
1.strlen遇到\0才结束长度的判断,你malloc后数据没初始化就用strlen去判断长度,得到的结果是未知的
2.一定要自己加上
h_5_hao 2009-01-08
  • 打赏
  • 举报
回复
关于开辟空间的问题
C++堆、栈、自由存储区、全局/静态存储区和常量存储区

一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。


二、例子程序
这是一个前辈写的,非常详细
//main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}


二、堆和栈的理论知识
2.1申请方式
stack:
由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间
heap:
需要程序员自己申请,并指明大小,在c中malloc函数
如p1 = (char *)malloc(10);
在C++中用new运算符
如p2 = (char *)malloc(10);
但是注意p1、p2本身是在栈中的。


2.2
申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,
会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

2.3申请大小的限制
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。


2.4申请效率的比较:
栈由系统自动分配,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。

2.5堆和栈中的存储内容
栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。

2.6存取效率的比较

char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在运行时刻赋值的;
而bbbbbbbbbbb是在编译时就确定的;
但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。
比如:
#include
void main()
{
char a = 1;
char c[] = "1234567890";
char *p ="1234567890";
a = c[1];
a = p[1];
return;
}
对应的汇编代码
10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al
第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。


2.7小结:
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

1、内存分配方面:

堆:一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式是类似于链表。可能用到的关键字如下:new、malloc、delete、free等等。

栈:由编译器(Compiler)自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

2、申请方式方面:

堆:需要程序员自己申请,并指明大小。在c中malloc函数如p1 = (char *)malloc(10);在C++中用new运算符,但是注意p1、p2本身是在栈中的。因为他们还是可以认为是局部变量。

栈:由系统自动分配。 例如,声明在函数中一个局部变量 int b;系统自动在栈中为b开辟空间。

3、系统响应方面:

堆:操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样代码中的delete语句才能正确的释放本内存空间。另外由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

4、大小限制方面:

堆:是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

栈:在Windows下, 栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是固定的(是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。

5、效率方面:

堆:是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便,另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。

栈:由系统自动分配,速度较快。但程序员是无法控制的。

6、存放内容方面:

堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。

栈:在函数调用时第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈,然后是函数中的局部变量。 注意: 静态变量是不入栈的。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。

7、存取效率方面:

堆:char *s1 = "Hellow Word";是在编译时就确定的;

栈:char s1[] = "Hellow Word"; 是在运行时赋值的;用数组比用指针速度要快一些,因为指针在底层汇编中需要用edx寄存器中转一下,而数组在栈上直接读取。

这里面有malloc开辟的说明 以及程序运行内存的分配
很详细啦 大概看下 慢慢学习吧 呵呵
h_5_hao 2009-01-08
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 sun68807 的回复:]
引用 1 楼 Idle_ 的回复:
1. strlen的原理就是从第一个位置开始计数直到遇到'\0'。
2. malloc分配内存时并不将所分配的内存清零。


1.1楼你是说:strlen是以\0为标记,然后计数,因此用strlen来量malloc出来的内存空间,是不可能得到正确结果的,得到的只是一个随机变量。

2.你说malloc不将内存清零,什么意思?是不是说当字符串是写在malloc出来的内存上的时候,就必须自己加上\0?
[/Quote]

strlen是一直循环相加 知道遇见'\0'为止
malloc是随即开辟空间 malloc开辟的空间内存上本来写的是什么就是什么 不会清零
h_5_hao 2009-01-08
  • 打赏
  • 举报
回复
#include <stdio.h>
#include<stdlib.h>
char*CreateSearchPath(const char *prefix,const char *dirName) ;
int main()
{
char *a = "C:\\temp\\*";
char *b = "subDir";
char *c = CreateSearchPath(a,b);
printf("%s",c);
free(c);


system("pause");
return 0;
}

char*CreateSearchPath(const char *prefix,const char *dirName)
{
int i=0,j=0,len1=0,len2=0;
for ( i=0;*(prefix+i)!='\0';++i)
{

}
len1=i;
if (*(prefix+i-1)=='*')
{

len1=i-1;
}
for (j=0;*(dirName+j)!='\0';++j)
{

}
len2=j;
char*new_path=(char*)malloc((len1+len2+3)*sizeof(char));
for (i=0;*(prefix+i)!='\0'&&*(prefix+i)!='*';++i)
{
*(new_path+i)=*(prefix+i);
}
for (j=0;*(dirName+j)!='\0';j++)
{
*(new_path+i+j)=*(dirName+j);
}
*(new_path+i+j)='\\' ;

*(new_path+i+j+1)='*';
*(new_path+i+j+2)='\0';

return new_path;
}
这是我写的代码
sun68807 2009-01-08
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 Idle_ 的回复:]
1. strlen的原理就是从第一个位置开始计数直到遇到'\0'。
2. malloc分配内存时并不将所分配的内存清零。
[/Quote]

1.1楼你是说:strlen是以\0为标记,然后计数,因此用strlen来量malloc出来的内存空间,是不可能得到正确结果的,得到的只是一个随机变量。

2.你说malloc不将内存清零,什么意思?是不是说当字符串是写在malloc出来的内存上的时候,就必须自己加上\0?
wyswyg63 2009-01-08
  • 打赏
  • 举报
回复
是不是调用malloc的来的字符串??
malloc只分配空间,那里来的字符串啊。
只有分配空间以后,自己向空间里写字符串。
同意ls
阿呆_ 2009-01-08
  • 打赏
  • 举报
回复
1. strlen的原理就是从第一个位置开始计数直到遇到'\0'。
2. malloc分配内存时并不将所分配的内存清零。

69,373

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧