C strlen使用指针

C strlen使用指针,c,C,我见过使用指针的strlen的标准实现: int strlen(char * s) { char *p = s; while (*p!='\0') p++; return p-s; } 我知道这是可行的,但当我尝试用另外3种方法(现在就学习指针算术)来做这件事时,我想知道它们有什么问题 这与这本书的内容有些相似。这是错的吗 int strlen(char * s) { char *p = s; while (*p) p++; return p-s; }

我见过使用指针的strlen的标准实现:

int strlen(char * s) {
  char *p = s;
  while (*p!='\0')
    p++;
  return p-s;
}
我知道这是可行的,但当我尝试用另外3种方法(现在就学习指针算术)来做这件事时,我想知道它们有什么问题

  • 这与这本书的内容有些相似。这是错的吗

    int strlen(char * s) {
      char *p = s;
      while (*p)
        p++;
      return p-s;
    }
    
  • 我想如果我传递一个空字符串,但仍然给我0,这是错误的,因为p是预增量:(现在它返回我5)

  • 解决了这个问题,执行post增量并返回+1

    int strlen(char * s) {
      char *p = s;
      while (*p++)
        ;
      return p-s;
    }
    
  • 1) 我觉得不错。我个人更喜欢对“\0”进行显式比较,这样就可以清楚地看出,在上下文不清楚的情况下,您并不打算(例如)将
    p
    与空指针进行比较

    2) 程序运行时,称为堆栈的内存区域未初始化。局部变量存在于此。您编写程序的方式将
    p
    放入堆栈中(如果您将其设置为
    const
    或使用
    malloc
    ,它几乎肯定会存在于其他地方)。当你看
    *p
    时,你会看到堆栈。如果字符串长度为0,则与
    charp[1]={0}
    相同。预递增查找紧跟在
    \0
    之后的字节,因此您查找的是未定义的内存。这里有龙

    3) 我认为这里没有问题:)正如你所看到的,它总是比正确答案多返回一个

    附录:如果您喜欢这种样式,也可以使用for循环编写:

    size_t strlen(char * s) {
        char *p = s;
        for (; *p != '\0'; p++) {}
        return p - s;
    }
    
    或者(更容易出错)

    此外,strlen不能返回负数,因此应该使用无符号值<代码>大小\u t更好。

    1)在我看来很好。我个人更喜欢对“\0”进行显式比较,这样就可以清楚地看出,在上下文不清楚的情况下,您并不打算(例如)将
    p
    与空指针进行比较

    2) 程序运行时,称为堆栈的内存区域未初始化。局部变量存在于此。您编写程序的方式将
    p
    放入堆栈中(如果您将其设置为
    const
    或使用
    malloc
    ,它几乎肯定会存在于其他地方)。当你看
    *p
    时,你会看到堆栈。如果字符串长度为0,则与
    charp[1]={0}
    相同。预递增查找紧跟在
    \0
    之后的字节,因此您查找的是未定义的内存。这里有龙

    3) 我认为这里没有问题:)正如你所看到的,它总是比正确答案多返回一个

    附录:如果您喜欢这种样式,也可以使用for循环编写:

    size_t strlen(char * s) {
        char *p = s;
        for (; *p != '\0'; p++) {}
        return p - s;
    }
    
    或者(更容易出错)


    此外,strlen不能返回负数,因此应该使用无符号值<代码>大小\u t甚至更好。

    版本1很好-
    而(*p!='\0')
    相当于
    而(*p!=0)
    ,相当于
    而(*p)

    在原始代码和版本1中,指针
    p
    当且仅当
    *p
    不是
    0
    (注意,您不在字符串的末尾)时才是高级的


    无论
    *p
    是否为
    0
    ,第2版和第3版都将升级
    p
    *p++
    计算为
    p
    所指向的字符,并作为副作用前进
    p
    *++p
    计算为
    p
    所指向的字符后面的字符,并作为副作用前进
    p
    。因此,版本2和版本3将始终前进
    p
    超过字符串的末尾,这就是您的值关闭的原因

    版本1很好-
    while(*p!='\0')
    相当于
    while(*p!=0)
    ,这相当于
    while(*p)

    在原始代码和版本1中,指针
    p
    当且仅当
    *p
    不是
    0
    (注意,您不在字符串的末尾)时才是高级的


    无论
    *p
    是否为
    0
    ,第2版和第3版都将升级
    p
    *p++
    计算为
    p
    所指向的字符,并作为副作用前进
    p
    *++p
    计算为
    p
    所指向的字符后面的字符,并作为副作用前进
    p
    。因此,版本2和版本3将始终前进
    p
    超过字符串的末尾,这就是您的值关闭的原因

    当您比较
    strlen
    替换函数的性能时,会遇到的一个问题是,与长字符串的实际
    strlen
    函数相比,它们的性能会受到影响?为什么?
    strlen
    在搜索字符串结尾时,每次迭代处理超过一个字节。如何实现更高效的替换

    没那么难。基本方法是每次迭代查看4字节,并根据在这4字节中找到nul字节的位置调整返回。您可以执行以下操作(使用数组索引):

    您可以使用指针和掩码执行完全相同的操作:

    size_t strsz (const char *s) {
        size_t len = 0;
        for(;;) {
            unsigned x = *(unsigned*)s;
            if((x & 0xff) == 0) return len;
            if((x & 0xff00) == 0) return len + 1;
            if((x & 0xff0000) == 0) return len + 2;
            if((x & 0xff000000) == 0) return len + 3;
            s += 4, len += 4;
        }
    }
    

    无论哪种方式,您都会发现每次迭代都会进行4字节的比较,其性能相当于strlen本身。

    当您比较strlen替换函数的性能时,您会遇到一个问题:与长字符串的实际strlen函数相比,它们的性能会受到影响吗?为什么?
    strlen
    在搜索字符串结尾时,每次迭代处理超过一个字节。如何实现更高效的替换

    没那么难。基本方法是每次迭代查看4字节,并根据在这4字节中找到nul字节的位置调整返回。您可以执行以下操作(使用数组索引):

    你能行
    size_t strsz_idx (const char *s) {
        size_t len = 0;
        for(;;) {
            if (s[0] == 0) return len;
            if (s[1] == 0) return len + 1;
            if (s[2] == 0) return len + 2;
            if (s[3] == 0) return len + 3;
            s += 4, len += 4;
        }
    }
    
    size_t strsz (const char *s) {
        size_t len = 0;
        for(;;) {
            unsigned x = *(unsigned*)s;
            if((x & 0xff) == 0) return len;
            if((x & 0xff00) == 0) return len + 1;
            if((x & 0xff0000) == 0) return len + 2;
            if((x & 0xff000000) == 0) return len + 3;
            s += 4, len += 4;
        }
    }