字串複製:strcpy()、strncpy()
每次都為了有沒有包含字串結尾字元「\0」而煩惱,就做個筆記吧。
前言:sizeof()與strlen()
進入正題前,先看看字串長度,順便複習陣列和指標。
#include <stdio.h>
#include <string.h>
void main()
{
char arr1[] = {'1', '2', '3', '\0'};
char arr2[] = "123";
char *ptr = "123";
printf("--- arr1 ---\n");
printf("length of string : %lu\n", strlen(arr1));
printf("size of array : %lu\n", sizeof(arr1));
printf("--- arr2 ---\n");
printf("length of string : %lu\n", strlen(arr2));
printf("size of array : %lu\n", sizeof(arr2));
printf("--- ptr_arr1 ---\n");
printf("length of string : %lu\n", strlen(&arr1[0]));
printf("size of pointer : %lu\n", sizeof(&arr1[0]));
printf("--- ptr ---\n");
printf("length of string : %lu\n", strlen(ptr));
printf("size of pointer : %lu\n", sizeof(ptr));
}
輸出如下:
--- arr1 ---
length of string : 3
size of array : 4
--- arr2 ---
length of string : 3
size of array : 4
--- ptr_arr1 ---
length of string : 3
size of pointer : 8
--- ptr ---
length of string : 3
size of pointer : 8
arr1和arr2是等效的,只是若要用arr2的宣告方式,要#include <string.h>。strlen()回傳長度不包含串結尾字元「\0」,sizeof()輸入若為陣列,才不管裡面的值是什麼,一律回傳整個陣列宣告長度;sizeof()輸入若為指標,將回傳儲存一個位址所需要的大小,在64位元的作業系統中,是8-Byte,也就是64-bit。
strncpy()
函式宣告
顯示「.」代表未改變,保持原始值。
顯示「_」代表字串結尾字元「\0」。
char *strncpy(char *dest, const char *src, size_t n);
測試範例
#include <stdio.h>
#include <string.h>
void main()
{
char src[] = "1234";
char arr[7];
int i, n;
for (n = 0; n <= sizeof(arr); n++) {
memset(arr, 0xff, sizeof(arr));
printf("N = %2d: ", n);
strncpy(arr, src, n);
for (i = 0; i < sizeof(arr); i++) {
if (arr[i] == (char)0xff)
printf("%c ", '.');
else if (arr[i] == '\0')
printf("%c ", '_');
else
printf("%c ", arr[i]);
}
printf("\n");
}
}
輸出如下:顯示「.」代表未改變,保持原始值。
顯示「_」代表字串結尾字元「\0」。
N = 0: . . . . . . .
N = 1: 1 . . . . . .
N = 2: 1 2 . . . . .
N = 3: 1 2 3 . . . .
N = 4: 1 2 3 4 . . .
N = 5: 1 2 3 4 _ . .
N = 6: 1 2 3 4 _ _ .
N = 7: 1 2 3 4 _ _ _
若N超出strlen(src),會補'\0',若想src[]全部複製,可以選擇N = strlen(src) + 1即可,若想讓陣列看起來更乾淨,可以選擇N = sizeof(arr)。
strcpy()
函式宣告
顯示「.」代表未改變,保持原始值。
顯示「_」代表字串結尾字元「\0」。
char *strcpy(char *dest, const char *src);
測試範例
#include <stdio.h>
#include <string.h>
void main()
{
char src[] = "1234";
char arr[7];
int i, n;
memset(arr, '.', sizeof(arr));
strcpy(arr, src);
for (i = 0; i < sizeof(arr); i++) {
if (arr[i] == '\0')
printf("%c ", '_');
else
printf("%c ", arr[i]);
}
printf("\n");
}
輸出如下:顯示「.」代表未改變,保持原始值。
顯示「_」代表字串結尾字元「\0」。
1 2 3 4 _ . .
使用strcpy(arr, src)的效果,與strncpy(arr, src, strlen(src) + 1)等效。溢位
使用strcpy(),當strlen(src) + 1 > sizeof(arr),超出陣列arr的範圍會照樣複製,例如:
紅底格子為溢位的位址。
使用strncpy(),當n > sizeof(arr),超出陣列arr的範圍會照樣複製或補'\0',例如:
紅底格子為溢位的位址。建議strncpy的n參數選用sizeof(arr),就可以確保程式安全,不會改動到陣列arr[]範圍以外的值。
char src[] = "1234";
char arr[4];
strcpy(arr, src);
得到的arr將是
| '1' | '2' | '3' | '4' | '\0' |
使用strncpy(),當n > sizeof(arr),超出陣列arr的範圍會照樣複製或補'\0',例如:
char src[] = "1234";
char arr[7];
size_t n = 10;
strncpy(arr, src, n);
得到的arr將是
| '1' | '2' | '3' | '4' | '\0' | '\0' | '\0' | '\0' | '\0' | '\0' |
留言
張貼留言