C 中的切片与 Python 相比

Slicing in C compared with Python

我一直在想像Python的拼接那样的子串方法,例如'hello'[2:4].

OLD:指针newtoret(指向return)是相同的,但是当存储在hello,它有一个新地址。有没有办法维护地址并打印出切片?

NEW:将字符放入缓冲区的最佳方法是什么?

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

//char * substr(char *str, int start, int end);
//void substr(char *str, int start, int end);
void get_substr(char *str, int start, int end, char *buffer);

int main() {
    char word[] = "Clayton";
    char buffer[15];
    printf("buffer is now %s",get_substr(word,2,5,buffer);
    return 0;
}


void get_substr(char *str, int start, int end, char *buffer) {
    int length = end - start;
    printf("length %d\n",length);
    //char buffer[length]; //init normal array    
    //assign values from *str
    int i;
    for (i = 0; i < length; i++) {
        buffer[i] = *(str+i+start);
    }
}


//char * substr(char *str, int start, int end) {
/* char * substr(char *str, int start, int end) {
    int length = end - start;
    printf("length %d\n",length);
    char buffer[length]; //init normal array    
    //assign values from *str
    int i;
    for (i = 0; i < length; i++) {
        buffer[i] = *(str+i+start);
        printf("i=%d buffer[i]=%c ptr=%c\n",i,buffer[i],*(str+i+start));
    }
    //add endline if not present
    if (buffer[length] != '[=11=]') {
        buffer[length] = '[=11=]';
        printf("buffer[%d] is %c\n",length,buffer[length]);
        printf("0 added\n");
    }
    printf("buffer %s %p\n",buffer,buffer);
    printf("len(buffer) is %d\n",strlen(buffer));
    char *toret;
    toret = (char*) &buffer;
    printf("toret %s %p\n",toret,toret);
    return toret;
} */

抱歉,这可能是重复的,但我无法在此域中找到相同的示例。 我是 C 新手!

未测试,但类似如下的内容应该有效:

char name[] = "Clayton";
int slice_begin = 0, slice_end = 3;
printf("%.*s", slice_end - slice_begin, name + slice_begin);

Update 基于这个技巧,你可以使用两个变量来表示一个子字符串:一个指向切片开始的指针,和一个表示长度的整数。

您不能 return 指向在函数内局部声明的缓冲区的指针。该内存驻留在堆栈中,下一个函数调用可能会覆盖该内存。如果要将 return 分配给调用函数,则需要使用 malloc 创建所需的内存,完成后需要使用 free 进行清理有了它。

也就是说,在被调用函数中分配内存并 return 它通常是不明智的。为了防止调用者忘记清理内存,我建议请求一个缓冲区,子字符串将被复制到其中。

我会将函数签名更改为 return 空值,并占用一个额外的缓冲区,子字符串将被复制到其中:

void get_substr(char *str, int start, int end, char *buffer)

然后,在你的调用函数中,你可以这样做:

int main() {
    char name[] = "Clayton";
    char buffer[10];

    get_substr(name, 0, 3, buffer);
    /* "Cla" now copied into buffer */

    printf("%s", buffer);
    return 0;
}

或者,由于这是一个子字符串函数,并且您知道该字符串完全包含在原始字符串中,您可以 return 字符串长度的大小和指向字符串开头的指针(在原始字符串内)。

您的签名可能如下所示:

int substr(char *str, int start, int end, char *substr)

用法可能如下所示:

int main() {
    char name[] = "Clayton";
    char *substr;
    int substr_len = substr(name, 0, 3, substr);
    /* substr now points to name, substr_len = 3 */

    /* Copy substring to buffer to print */
    char buffer[10];
    strncpy(buffer, substr, substr_len);

    printf("%s", buffer);
    return 0;
}

既然你想模仿 Python 的切片,我会选择类似的东西:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

char *slice(char *string, int start, int stop, int step) {
    size_t string_length = ceil(fabs((stop - start) / (float) step));

    char *new_string = malloc(string_length + 1);

    for (int i = start, j = 0; j < string_length; i += step, j++) {
        new_string[j] = string[i];
    }

    new_string[string_length] = '[=10=]';

    return new_string;
}

int main() {
    char *name = "Clayton";

    char *hello = slice(name, 0, 3, 1);

    printf("%s\n", hello);

    free(hello);

    char *letters = "abcdefghijklmnopqrstuvwxyz";

    char *goodbye = slice(letters, strlen(letters) - 1, -1, -1);

    printf("%s\n", goodbye);

    free(goodbye);

    return 0;
}

输出:

Cla
zyxwvutsrqponmlkjihgfedcba