簡體   English   中英

strncpy 與直接分配段錯誤

[英]strncpy vs direct assignment seg fault

以下代碼在沒有段錯誤的情況下運行

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

struct node {
    char *data;
    struct node *next;
};

int main(void)
{   
    struct node *head = malloc(sizeof(struct node));
    
    head->data = "test";
    printf("data: %s\n", head->data);

    return 0;
}

當我將代碼切換為

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

struct node {
    char *data;
    struct node *next;
};

int main(void)
{   
    struct node *head = malloc(sizeof(struct node));
    
    strncpy(head->data, "test", 512);
    printf("data: %s\n", head->data);

    return 0;
}

我收到段錯誤並被迫將我的節點屬性數據切換為 char 數據 [512] 類型。 為什么這是必需的? 我認為 arrays 本質上是指針,所以這種行為對我來說沒有意義。

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

struct node {
    char data[512];
    struct node *next;
};

int main(void)
{   
    struct node *head = malloc(sizeof(struct node));
    
    strncpy(head->data, "test", 512);
    printf("data: %s\n", head->data);

    return 0;
}

我希望指針和 arrays 都可以以相同的方式分配字符串值。

在這份聲明中

head->data = "test";

具有數組類型char[5]的字符串文字被隱式轉換為指向其第一個元素的指針,並且該指針被分配給指針head->data

在這份聲明中

strncpy(head->data, "test", 512);

您正在使用未初始化的指針head->data並嘗試將整個字符串文字復制到該指針指向的具有不確定值的 memory 。 這會調用未定義的行為。

我認為 arrays 本質上是指針,所以這種行為對我來說沒有意義。

Arrays 不是指針。 在大多數情況下,它們可以隱式轉換為指向其第一個元素的指針,但這並不意味着 arrays 是指針。

考慮下面的簡單演示程序。

#include <stdio.h>

int main( void )
{
    char data[512];
    char *p = data;

    printf( "sizeof( data ) = %zu\n", sizeof( data ) );
    printf( "sizeof( p ) = %zu\n", sizeof( p ) );
}

它的 output 可能看起來像

sizeof( data ) = 512
sizeof( p ) = 8

在第二個片段(崩潰的片段)中,您為node結構分配了 memory,其中包括指針data 然而,這個指針永遠不會被初始化,它指向某個任意的 memory 地址(或者只是NULL ),這意味着寫入它是未定義的行為,而且確實可能只是段錯誤。

要使其指向有效的 memory 地址,您必須顯式分配它:

struct node *head = malloc(sizeof(struct node));
head->data = malloc(sizeof(char) * 512 /* or some other size, of course */);

為什么這是必需的? 我認為 arrays 本質上是指針,所以這種行為對我來說沒有意義。

指針只是指針,它們占用的唯一 memory 是存儲地址所需的 memory。 如果你想要一個指針指向動態分配的memory,你需要自己分配它。

例子:

struct node {
    char *data;
    struct node *next;
};

struct node *create_node(const char *str) {
    struct node *nn = malloc(sizeof *nn);
    if(nn) {
        nn->data = strdup(str); // allocate strlen(str)+1 bytes and copy the string
        if(nn->data) {          // strdup was successful
            nn->next = NULL;
        } else {                // strdup failed
            free(nn);
            nn = NULL;
        }
    }
    return nn;
}

void destroy_node(struct node *n) {
    free(n->data);
    free(n);
}

我認為 arrays 本質上是指針

數組與指針:

數組可能會衰減為表達式中的指針和 function 參數,並且數組訪問可能會被編譯器重寫為指針訪問,但它們不可互換。 數組名是地址,指針是地址的地址。


為什么這是必需的?

聲明一個指針只會為指針分配 memory。

您可以通過兩種方式初始化指針:

  • 使用字符串文字:

     ptr = "abcd";

    最初, ptr是不確定的。 但這改變了它指向的內容,現在它指向一個字符串文字。 編譯器會將字符串文字的第一個元素的地址存儲在ptr中。

    如果你對一個做同樣的事情
    大批:

     char s[] = "String";

    然后嘗試更改其值:

     s = "String2"; /* error: assignment to expression with array type */

    它不會編譯,因為 arrays 與指針不同,它不是可修改的左值。 你不能改變它的價值。

  • 或者給它分配memory然后
    寫信給它。

     errno = 0; ptr = malloc (size); if (;ptr) { errno = ENOMEM; perror ("malloc ()"). deal with error here... }

    現在你可以使用strcpy ()來復制它了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM