Strlen、Malloc 和地址运算

Strlen, Malloc and address arithmetic

需要一些帮助来分解这个 C 函数。我被困在 malloc 线上。我不明白“+8”在做什么 and/or 为什么它在那里。我的研究表明它与地址运算有关。另外,我不介意一些帮助来检查我对每行代码的其余细分(注释)是否正确。

    // Prints help message to the console
    // Returns a string
    char * helloWorld(char * name) {                                //The * is a pointer to an address. (char * name) = the address to a char pointer stored/passed via name.
        char * answer = malloc(strlen(name) + 8);                   //syntax = (cast-type*) malloc(byte-size); answer has a * because malloc returns a void pointer. The * deferences the pointer
                                                                    //and tells the program to use the value at that member address.
                                                                    //strlen returns a 
        printf("This prints to the console when you Run Tests");
        strcpy(answer, "Hello, ");                                  //This returns a pointer to the destination string dest. char *strcpy(char *dest, const char *src)
                                                                //(answer {dest}, "Hello, "{string to be copied to dest}) *dest= The value at the pointer of src("Hello, ") will be assigned.
        strcat(answer {des}, name {src});               //char *strcat(char *dest, const char *src) --> appends the string pointed to by src to the end of the string pointed to by dest.
        return answer;                                  //adds name to the end of answer. -->Hello, name.
    }

它需要足够的内存用于输入字符串(strlen 的结果)、前缀 "Hello, "(7 个字符)和终止 NUL 字符(1 个字符),因此将 8 添加到strlen 获取分配所需的总内存。

正如您所指出的,这有点令人困惑(幻数通常是这样),而且很脆弱(对前缀的每次更改都需要对看似无关的幻数进行匹配更改),因此在更好的代码中您可以做一些事情喜欢:

// Prints help message to the console
// Returns a string
char * helloWorld(char * name) {                                //The * is a pointer to an address. (char * name) = the address to a char pointer stored/passed via name.
    static const char PREFIX[] = "Hello, ";
    // Conveniently, the size of the array includes the NUL too
    char * answer = malloc(strlen(name) + sizeof(PREFIX));                   //syntax = (cast-type*) malloc(byte-size); answer has a * because malloc returns a void pointer. The * deferences the pointer
                                                                //and tells the program to use the value at that member address.
                                                                //strlen returns a 
    printf("This prints to the console when you Run Tests");
    strcpy(answer, PREFIX);                                  //This returns a pointer to the destination string dest. char *strcpy(char *dest, const char *src)
                                                            //(answer {dest}, "Hello, "{string to be copied to dest}) *dest= The value at the pointer of src("Hello, ") will be assigned.
    strcat(answer {des}, name {src});               //char *strcat(char *dest, const char *src) --> appends the string pointed to by src to the end of the string pointed to by dest.
    return answer;                                  //adds name to the end of answer. -->Hello, name.
}

这清楚地说明了为什么要增加分配的长度而没有与前缀本身直接相关的幻数。

跟地址运算完全没有关系。 strlen(name) + 8 就是这样;将长度 name 加 8。

8 是由字符串长度 Hello, (7 个字节)加上结果字符串的空终止符的 1 个字节组成的幻数。

My research revealed it has something to do with address arithmetic.

这是错误的。这里不涉及地址运算。

您没有告诉我们您希望看到什么而不是 +8

如果您直接使用 strlen(name),则没有终止 0 字节的空间。

而且也只有复制空间name到新的内存中。但是您想在内存区域的开头添加 "Hello, " 。 该字符串占用 7 个字节。

最后,"Hello, " 的 7 个字节和以 0 字节终止字符串的 1 个字节,总共 8 个字节,您在分配内存时必须添加这些字节。

这里没有指针运算。 malloc 函数被告知分配 strlen(name) + 8 字节的内存,即足够 name 加上额外的 7 个字符和一个空终止字节。

以下行将字符串 "Hello, " 复制到 answer,然后将 name 连接到它上面。前导字符串 "Hello, " 有 7 个字符,因此这就是分配时额外的 7 个字符。

如果您写信回答,您必须确保它有足够的 space 来容纳整个结果字符串。因为这个大小只在运行时需要,所以 space 被分配。 (第二个原因是你 return 它的地址,所以你不能把它放在堆栈上)。

如果您查看您看到的代码,答案将是 Hello, (长度 = 7)加上名称(长度 = strlen(name))加上终止空字节(长度 = 1) .所以 strlen(name) + 8 将完全符合答案。

+8 这里与其他答案提到的指针算法无关。在 malloc 中,您指定要在内存中分配的字节数。 strlen(name)name字符串中char的个数,8是字符串文字“Hello,”的字节数,包括空终止符。

从这行注释开始,char * 没有取消对 void 指针的引用。它是 char* 的变量声明,其中右侧可以隐式转换为 char*.

char * answer = malloc(strlen(name) + 8); // syntax = (cast-type*) malloc(byte-size); answer has a * because malloc returns a void pointer. The * deferences the pointer

假设函数必须return一个字符串,例如

"Hello, N6DYN"

其中名称“N6DYN”通过参数名称传递给函数。

所以魔术数字 8 表示存储在内存中的字符串 "Hello, " 的大小

{ 'H', 'e', 'l', 'l', 'o', ',', ' ', '[=11=]' }

函数的声明和定义如下面的演示程序所示

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

char * helloWorld( const char * name ) 
{
    const char *hello = "Hello, ";

    char *answer = malloc( strlen( name ) + strlen( hello ) + 1 );                           

    if ( answer != NULL )
    {
        strcpy( answer, hello );                                                                           
        strcat( answer, name );
    }

    return answer;
}

int main( void )
{
    char name[100] = "";

    printf( "Enter your name: " );

    scanf( "%99s", name );

    char *hello = helloWorld( name );

    if ( hello != NULL ) puts( hello );

    free( hello );
}

而不是函数中的这些行

const char *hello = "Hello, ";

char *answer = malloc( strlen( name ) + strlen( hello ) + 1 );                           

你也可以这样写

const char hello[] = "Hello, ";

char *answer = malloc( strlen( name ) + sizeof( hello ) );                           

在这种情况下 sizeof( hello ) 等于 8 如果写 strlen( hello ) + 1.

是相同的值