จุดประสงค์ของstrdup()
ฟังก์ชั่นใน C คืออะไร?
strdupa
เป็นอันตรายและไม่ควรใช้เว้นแต่คุณจะเห็นว่าstrlen
มีขนาดเล็กมาก แต่คุณสามารถใช้อาร์เรย์ขนาดคงที่บนสแต็กได้
strdup
/ strdupa
หมายความว่าอะไรในโปแลนด์?
จุดประสงค์ของstrdup()
ฟังก์ชั่นใน C คืออะไร?
strdupa
เป็นอันตรายและไม่ควรใช้เว้นแต่คุณจะเห็นว่าstrlen
มีขนาดเล็กมาก แต่คุณสามารถใช้อาร์เรย์ขนาดคงที่บนสแต็กได้
strdup
/ strdupa
หมายความว่าอะไรในโปแลนด์?
คำตอบ:
ดูเหมือนว่าหากคุณคุ้นเคยกับวิธีการย่อที่ C และ UNIX กำหนดคำมันซ้ำกับสตริง :-)
โปรดทราบว่าจริงๆแล้วมันไม่ได้เป็นส่วนหนึ่งของมาตรฐาน ISO C เอง(a) (เป็น POSIX) มันทำอย่างมีประสิทธิภาพเช่นเดียวกับรหัสต่อไปนี้:
char *strdup(const char *src) {
char *dst = malloc(strlen (src) + 1); // Space for length plus nul
if (dst == NULL) return NULL; // No memory
strcpy(dst, src); // Copy the characters
return dst; // Return the new string
}
ในคำอื่น ๆ :
มันพยายามจัดสรรหน่วยความจำให้เพียงพอเพื่อเก็บสตริงเก่า (บวกอักขระ '\ 0' เพื่อทำเครื่องหมายจุดสิ้นสุดของสตริง)
หากการจัดสรรล้มเหลวที่จะกำหนดerrno
ไปENOMEM
และกลับNULL
ทันที การตั้งค่าของerrno
การENOMEM
เป็นสิ่งที่malloc
ไม่อยู่ใน POSIX strdup
ดังนั้นเราจึงไม่จำเป็นต้องทำมันอย่างชัดเจนของเรา หากคุณไม่ได้ตาม POSIX, ISO C ไม่จริงอาณัติการดำรงอยู่ของENOMEM
ผมจึงไม่ได้รวมที่นี่(ข)
มิฉะนั้นการจัดสรรจะใช้งานได้ดังนั้นเราจึงคัดลอกสตริงเก่าไปยังสตริงใหม่(c)และส่งคืนที่อยู่ใหม่ (ซึ่งผู้โทรต้องรับผิดชอบในการปลดปล่อยในบางจุด)
โปรดทราบว่าเป็นคำจำกัดความของแนวคิด ผู้เขียนไลบรารี่รายใดที่มีมูลค่าเงินเดือนของพวกเขาอาจมอบโค้ดที่ได้รับการปรับแต่งอย่างมากซึ่งกำหนดเป้าหมายไปยังโปรเซสเซอร์ที่ใช้งานอยู่
(a)อย่างไรก็ตามฟังก์ชั่นที่เริ่มต้นด้วยstr
และตัวอักษรพิมพ์เล็กถูกจองโดยมาตรฐานสำหรับทิศทางในอนาคต จากC11 7.1.3 Reserved identifiers
:
แต่ละส่วนหัวประกาศหรือกำหนดตัวระบุทั้งหมดที่ระบุไว้ในอนุประโยคย่อยที่เกี่ยวข้องและ * ทางเลือกประกาศหรือกำหนดตัวระบุที่ระบุไว้ในข้อย่อยคำสั่งย่อยห้องสมุดทิศทางในอนาคต **
ทิศทางในอนาคตสำหรับstring.h
สามารถพบได้ในC11 7.31.13 String handling <string.h>
:
ชื่อฟังก์ชั่นที่ขึ้นต้นด้วย
str
,mem
หรือwcs
และอาจเป็นตัวอักษรตัวพิมพ์เล็กในการประกาศใน<string.h>
ส่วนหัว
ดังนั้นคุณควรเรียกมันอย่างอื่นถ้าคุณต้องการความปลอดภัย
(b)การเปลี่ยนแปลงโดยทั่วไปจะแทนที่if (d == NULL) return NULL;
ด้วย:
if (d == NULL) {
errno = ENOMEM;
return NULL;
}
(c)โปรดทราบว่าฉันใช้strcpy
สิ่งนั้นเนื่องจากนั่นแสดงให้เห็นเจตนา ในการใช้งานบางอย่างมันอาจเร็วกว่า (เนื่องจากคุณทราบความยาวแล้ว) ในการใช้memcpy
เนื่องจากอาจอนุญาตให้ถ่ายโอนข้อมูลเป็นกลุ่มขนาดใหญ่หรือขนาน หรืออาจไม่ :-) การเพิ่มประสิทธิภาพมนต์ # 1: "การวัดอย่าเดา"
ไม่ว่าในกรณีใดคุณควรตัดสินใจไปเส้นทางนั้นคุณจะทำสิ่งที่ชอบ:
char *strdup(const char *src) {
size_t len = strlen(src) + 1; // String plus '\0'
char *dst = malloc(len); // Allocate space
if (dst == NULL) return NULL; // No memory
memcpy (dst, src, len); // Copy the block
return dst; // Return the new string
}
strdup
สำหรับสถานการณ์ที่คุณต้องการจัดสรรหน่วยความจำฮีปสำหรับการคัดลอกสตริง มิฉะนั้นคุณต้องทำด้วยตัวเอง หากคุณมีบัฟเฟอร์ขนาดใหญ่พอ (malloc'ed หรืออื่น ๆ ) strcpy
ใช่การใช้งาน
{ EDOM, EILSEQ, ERANGE }
รหัสข้อผิดพลาดที่จำเป็นเท่านั้น ได้อัปเดตคำตอบสำหรับบัญชีนี้แล้ว
char * strdup(const char * s)
{
size_t len = 1+strlen(s);
char *p = malloc(len);
return p ? memcpy(p, s, len) : NULL;
}
บางทีรหัสเป็นบิตเร็วกว่าด้วยstrcpy()
เป็น\0
ถ่านไม่จำเป็นที่จะค้นหาอีกครั้ง (แล้วมันก็มีstrlen()
)
return memcpy(malloc(len), s, len);
ตามที่ฉันต้องการความล้มเหลวในการจัดสรรมากกว่า NULL
ความล้มเหลวในการจัดสรร
NULL
ไม่ต้องชนกัน มันไม่ได้กำหนด หากคุณต้องการแน่ใจว่ามันขัดข้องให้เขียนการemalloc
เรียกที่abort
ล้มเหลว
emalloc
แม้ว่าจะไม่จำเป็นบน Solaris หรือ Linux ดังนั้นคุณจะใช้มันในอนาคตเมื่อคุณเขียนโค้ดบนแพลตฟอร์มอื่น ๆ
ไม่มีจุดที่จะตอบคำตอบอื่น ๆ อีกต่อไป แต่โปรดทราบว่าstrdup()
สามารถทำอะไรก็ได้ที่ต้องการจากมุมมอง C เนื่องจากไม่ใช่ส่วนหนึ่งของมาตรฐาน C ใด ๆ อย่างไรก็ตามมันถูกกำหนดโดย POSIX.1-2001
strdup()
แบบพกพา? ไม่ไม่สามารถใช้ได้ในสภาพแวดล้อมที่ไม่ใช่ POSIX (สามารถนำไปใช้งานได้เล็กน้อย) แต่ถ้าจะบอกว่าฟังก์ชั่น POSIX นั้นสามารถทำได้ทุกอย่างเลยทีเดียว POSIX เป็นอีกมาตรฐานที่ดีเท่า C และเป็นที่นิยมมากขึ้น
strdup
ฟังก์ชั่นเป็นส่วนขยาย ในการใช้งานดังกล่าวไม่มีการรับประกันว่าstrdup
จะทำงานในลักษณะเดียวกันกับฟังก์ชั่น POSIX ผมไม่ทราบว่าการใช้งานดังกล่าวใด ๆ แต่การดำเนินการที่ไม่ถูกต้องตามกฎหมายที่เป็นอันตรายอาจให้ด้วยเหตุผลทางประวัติศาสตร์และปฏิเสธความพยายามในการที่จะผ่านในchar *strdup(char *)
const char *
จากผู้ชาย strdup :
ฟังก์ชั่นจะกลับมาเป็นตัวชี้ไปยังสายใหม่ซึ่งเป็นซ้ำของสตริงที่ชี้ไปตามstrdup()
ชี้ส่งกลับสามารถส่งผ่านไปs1
free()
ตัวชี้ null ถูกส่งคืนหากไม่สามารถสร้างสตริงใหม่
strdup () ทำการจัดสรรหน่วยความจำแบบไดนามิกสำหรับอาร์เรย์อักขระรวมถึงอักขระสิ้นสุด '\ 0' และส่งคืนที่อยู่ของหน่วยความจำฮีป:
char *strdup (const char *s)
{
char *p = malloc (strlen (s) + 1); // allocate memory
if (p != NULL)
strcpy (p,s); // copy string
return p; // return the memory
}
ดังนั้นสิ่งที่มันทำคือให้เราสตริงอื่นเหมือนกับสตริงที่กำหนดโดยอาร์กิวเมนต์โดยไม่ต้องให้เราจัดสรรหน่วยความจำ แต่เรายังคงต้องทำให้เป็นอิสระในภายหลัง
มันทำให้สำเนาที่ซ้ำกันของสตริงที่ส่งผ่านโดยการเรียกใช้mallocและstrcpyของสตริงที่ส่งผ่านบัฟเฟอร์ malloc'ed จะถูกส่งกลับไปยังผู้โทรจึงจำเป็นต้องเรียกใช้ฟรีกับค่าตอบแทน
strdup
และstrndup
กำหนดไว้ในระบบที่รองรับ POSIX ดังนี้:
char *strdup(const char *str);
char *strndup(const char *str, size_t len);
strdup ()ฟังก์ชั่นจัดสรรหน่วยความจำเพียงพอสำหรับสำเนาของสตริงstr
ไม่คัดลอกและกลับชี้ไปมัน
ตัวชี้อาจถูกใช้เป็นอาร์กิวเมนต์ของฟังก์ชันในfree
ภายหลัง
หากหน่วยความจำไม่เพียงพอจะมีNULL
จะถูกส่งกลับและมีการตั้งค่าerrno
ENOMEM
strndup ()สำเนาฟังก์ชั่นที่มากที่สุดlen
ตัวละครจากสตริงstr
เสมอ null ยุติสตริงคัดลอก
สิ่งที่มีค่าที่สุดก็คือให้สตริงอื่นเหมือนกับสตริงแรกโดยไม่ต้องการให้คุณจัดสรรหน่วยความจำ (ตำแหน่งและขนาด) ด้วยตัวคุณเอง แต่ตามที่ระบุไว้คุณยังคงต้องทำให้เป็นอิสระ (แต่ไม่ต้องการการคำนวณปริมาณเช่นกัน)
คำสั่ง:
strcpy(ptr2, ptr1);
เทียบเท่ากับ (นอกเหนือจากความจริงแล้วสิ่งนี้เปลี่ยนแปลงตัวชี้):
while(*ptr2++ = *ptr1++);
โดย:
ptr2 = strdup(ptr1);
เทียบเท่ากับ:
ptr2 = malloc(strlen(ptr1) + 1);
if (ptr2 != NULL) strcpy(ptr2, ptr1);
ดังนั้นหากคุณต้องการสตริงที่คุณคัดลอกเพื่อใช้ในฟังก์ชั่นอื่น (เพราะมันถูกสร้างขึ้นในส่วนของฮีป) คุณสามารถใช้strdup
มิฉะนั้นstrcpy
ก็เพียงพอแล้ว
ฟังก์ชั่น strdup () เป็นชวเลขสำหรับสตริงที่ซ้ำกันมันใช้เวลาในพารามิเตอร์เป็นค่าคงที่สตริงหรือสตริงตัวอักษรและจัดสรรพื้นที่ว่างเพียงพอสำหรับสตริงและเขียนตัวอักษรที่สอดคล้องกันในพื้นที่ที่จัดสรรและในที่สุดก็ส่งกลับที่อยู่ของการจัดสรร พื้นที่ไปยังรูทีนการเรียก
strdup
char