我将在下个月指导一个ACM小组(去图),现在是时候谈论C中的字符串了。除了讨论标准的lib,strcpy
,strcmp
等。,我想给他们一些提示(类似于str[0] is equivalent to *str
,以及类似的东西)。
你知道任何名单(如备忘单)或你自己在这方面的经验吗?
我已经知道ACM比赛的书籍(这很好,特别是this),但我是在追逐交易的伎俩。
谢谢。
编辑:非常感谢大家。我会接受投票最多的答案,并且适当地支持我认为相关的其他人。我希望在这里做一个总结(就像我做here,asap)。我现在有足够的材料,我确信这极大地改善了字符串的会话。再一次,谢谢。
答案 0 :(得分:26)
很明显,但我认为知道字符串 nothing 比字节数组更重要,由零字节分隔。 你可能知道C字符串并不是所有用户友好的。
if( s1 == s2 )
doStuff(s1);
进行比较
您必须比较字符串中的每个字符。使用strcmp或更好的strncmp。
if( strncmp( s1, s2, BUFFER_SIZE ) == 0 )
doStuff(s1);
答案 1 :(得分:5)
滥用strlen()会大大恶化性能。
for( int i = 0; i < strlen( string ); i++ ) {
processChar( string[i] );
}
至少具有O(n 2 )时间复杂度,而
int length = strlen( string );
for( int i = 0; i < length; i++ ) {
processChar( string[i] );
}
至少具有O(n)时间复杂度。对于那些没有时间去思考它的人来说,这并不是那么明显。
答案 2 :(得分:3)
以下函数可用于实现非变异strtok
:
strcspn(string, delimiters)
strspn(string, delimiters)
第一个找到您传入的分隔符集中的第一个字符。第二个字符在您传入的分隔符集中找到第一个字符不。
我更喜欢这些strpbrk
,因为如果它们无法匹配,它们会返回字符串的长度。
答案 3 :(得分:3)
str[0]
相当于0[str]
,或者更为一般str[i]
为i[str]
而i[str]
为*(str + i)
。
NB
这不是特定于字符串,但它也适用于C数组
答案 4 :(得分:3)
stdlib 中的str
n
*
变体不一定为null终止目标字符串。
例如:来自MSDN关于strncpy
的文档:
strncpy函数复制 strSource的初始计数字符 到strDest并返回strDest。 如果 count小于或等于 strSource的长度,一个空字符 不会自动附加到 复制字符串。如果count更大 比strSource的长度, 目标字符串用null填充 字符长度计数。
答案 5 :(得分:2)
strtok
不是线程安全,因为它使用可变私有缓冲区在调用之间存储数据;你也不能交错或劝说strtok
电话。
更有用的替代方法是strtok_r
,只要你能就使用它。
答案 6 :(得分:2)
在使用字符串时将strlen()
与sizeof()
混淆:
char *p = "hello!!";
strlen(p) != sizeof(p)
sizeof(p)
在编译时产生指针的大小(4或8个字节),而strlen(p)
在运行时计算空终止的char数组的长度(本例中为7)
答案 7 :(得分:2)
kmm已经很好了。以下是我开始编写C代码时遇到的问题。
字符串文字有自己的内存部分,并且始终可以访问。因此,它们可以是函数的返回值。
字符串的内存管理,特别是高级库(不是libc)。如果字符串由函数返回或传递给函数,谁负责释放字符串?
什么时候应该使用“const char *”和何时使用“char *”。如果函数返回“const char *”,它会告诉我什么。
所有这些问题都不难学,但很难弄清楚你是否接受过教育。
答案 8 :(得分:1)
我发现char buff[0]
技术非常有用。
考虑:
struct foo {
int x;
char * payload;
};
VS
struct foo {
int x;
char payload[0];
};
请参阅https://stackoverflow.com/questions/295027
请参阅链接了解含义和变化
答案 9 :(得分:1)
我会讨论何时何时不使用strcpy
和strncpy
以及可能出现的问题:
char *strncpy(char* destination, const char* source, size_t n);
char *strcpy(char* destination, const char* source );
我还会提到ansi C stdlib字符串函数的返回值。例如,询问“if if if statement pass or failed?”
if (stricmp("StrInG 1", "string 1")==0)
{
.
.
.
}
答案 10 :(得分:1)
也许您可以通过以下示例
来说明sentinel'\ 0'的值char * a =“hello \ 0 world”; char b [100]; 的strcpy(B,A); 的printf(B);
在我的热情中,我曾经用手指烧过我使用strcpy()来复制二进制数据。它大部分时间都有效,但有时会神秘失败。当我意识到二进制输入有时包含零字节并且strcpy()将在那里终止时,揭开了神秘感。
答案 11 :(得分:0)
您可以提及索引寻址。
元素地址是基地址+索引* sizeof元素
答案 12 :(得分:0)
常见错误是:
char *p;
snprintf(p, 3, "%d", 42);
直到你使用最多sizeof(p)
字节才有效..然后有趣的事情发生了(欢迎来到丛林)。
<强>释强>
使用char * p,您将在堆栈上分配用于保存指针(sizeof(void*)
字节)的空间。这里正确的是分配一个缓冲区或只是在编译时指定指针的大小:
char buf[12];
char *p = buf;
snprintf(p, sizeof(buf), "%d", 42);
答案 13 :(得分:0)
我指出了过度依赖内置字符串函数的性能缺陷。
char* triple(char* source)
{
int n=strlen(source);
char* dest=malloc(n*3+1);
strcpy(dest,src);
strcat(dest,src);
strcat(dest,src);
return dest;
}
答案 14 :(得分:0)
指针和数组虽然具有相似的语法,但并不完全相同。给出:
char p [100]; char * p = a;对于数组a,没有指针存储在任何地方。 sizeof(a)!= sizeof(p),对于数组,它是内存块的大小,对于指针,它是指针的大小。如果您使用类似:sizeof(a)/ sizeof(a [0]),这一点就变得很重要。此外,你不能++ a,你可以使指针成为'const'字符的'const'指针,但是数组只能是'const'字符,在这种情况下你首先要初始化它。等等等
答案 15 :(得分:0)
如果可能,请使用strlcpy(而不是strncpy)和strlcat。
更好的是,为了让生活更安全,你可以使用如下的宏:
#define strlcpy_sz(dst, src) (strlcpy(dst, src, sizeof(dst)))