[英]My own strcat function with pointers does not work right
我是指針的新手,想學好它們。 所以這是我自己編寫strcat
function 的嘗試。 如果我只返回a
它會打印一些二進制的東西(我認為它應該打印解決方案),如果我返回*a
它說seg fault core dumped
我找不到錯誤。 任何幫助都被接受,謝謝。
#include <stdio.h>
#include <string.h>
int main() {
char *strcaT();
char *a = "first";
char *b = "second";
printf("%s", strcaT(a, b));
return 0;
}
char *strcaT(char *t, char *s) {
char buffer[strlen(t) + strlen(s) - 1];
char *a = &buffer[0];
for (int i = 0; i < strlen(s) + strlen(t); i++, t++) {
if (*t == '\n') {
for (int i = 0; i < strlen(s);i++) {
buffer[strlen(t) + i] = *(s + i);
}
}
buffer[i] = *(t + i);
}
return a;
}
該代碼有多種未定義行為的情況:
你在strcaT
中返回一個本地數組的地址,自動存儲,這意味着這個數組一旦離開scope,就不能再使用了,即:當你從function返回時。
緩沖區太小,它應該是 null 終結器的長度之和加 1。 你寫超出了這個本地數組的末尾,可能會覆蓋一些重要的信息,比如調用者的幀指針或返回地址。 這種未定義的行為很有可能導致分段錯誤。
您從第一個字符串復制strlen(t)+strlen(s)
字節,訪問超出t
的末尾。
目前尚不清楚為什么要測試'\n'
並在第一個字符串的換行符的 position 處復制第二個字符串。 字符串不以換行符結尾,它們可能包含換行符,但在 null 終止符處(字節值'\0'
或簡單的0
)。 fgets()
讀取的字符串可能在 null 終止符之前有一個尾隨換行符,但並非所有字符串都有。 在您的循環中,復制第二個字符串的效果會立即取消,因為您繼續從第一個字符串復制字節,甚至超出其 null 終止符。 您應該分別執行這些循環,首先從t
復制,然后從s
復制,無論任一字符串是否包含換行符。
另請注意,在main()
) 中本地聲明strcaT()
是非常糟糕的風格,甚至沒有適當的原型。 在main
function 及其參數列表之前聲明此 function。
這是分配連接字符串的修改版本:
#include <stdio.h>
#include <stdlib.h>
char *strcaT(const char *s1, const char *s2);
int main() {
const char *a = "first";
const char *b = "second";
char *s = strcaT(a, b);
if (s) {
printf("%s\n", s);
free(s);
}
return 0;
}
char *strcaT(const char *t, const char *s) {
char *dest = malloc(strlen(t) + strlen(s) + 1);
if (dest) {
char *p = dest;
/* copy the first string */
while (*t) {
*p++ = *t++;
}
/* copy the second string at the end */
while (*s) {
*p++ = *s++;
}
*p = '\0'; /* set the null terminator */
}
return dest;
}
但是請注意,這不是strcat
function 所做的:它在第一個字符串的末尾復制第二個字符串,因此在其數組中第一個字符串的末尾之后必須有足夠的空間來容納第二個字符串,包括 null終結者。 main()
中a
和b
的定義不適合這些語義,您必須創建a
足夠大的數組以容納兩個字符串。
這是使用這種方法的修改版本:
#include <stdio.h>
char *strcaT(char *s1, const char *s2);
int main() {
char a[12] = "first";
const char *b = "second";
printf("%s\n", strcaT(a, b));
return 0;
}
char *strcaT(char *t, const char *s) {
char *p = t;
/* find the end of the first string */
while (*p) {
*p++;
}
/* copy the second string at the end */
while (*s) {
*p++ = *s++;
}
*p = '\0'; /* set the null terminator */
return t;
}
返回一些局部變量是一個非常糟糕的主意,它會在 function 完成操作后被清除。 以下 function 應該可以工作。
char* strcaT(char *t, char *s)
{
char *res = (char*) malloc(sizeof(char) * (strlen(t) + strlen(s) + 1));
int count = 0;
for (int i = 0; t[i] != '\0'; i++, count++)
res[count] = t[i];
for (int i = 0; s[i] != '\0'; i++, count++)
res[count] = s[i];
res[count] = '\0';
return res;
}
對於初學者, function strcaT
應該 append 第二個參數指定的字符串到第一個參數指定的字符串的末尾。 所以第一個參數應該指向一個足夠大的字符數組來存儲附加的字符串。
您的 function 是不正確的,因為它至少返回一個指向局部可變長度字符數組的(無效)指針,該指針在退出 function 后將不再存在,而且該數組的大小小於存儲兩個字符串所需的大小,而不是
char buffer[strlen(t) + strlen(s) - 1];
^^^
它至少應該被聲明為
char buffer[strlen(t) + strlen(s) + 1];
^^^
並且可以聲明為 static
static char buffer[strlen(t) + strlen(s) + 1];
嵌套循環也沒有意義。
請注意,在調用 function 之前,您應該提供 function 原型。 在這種情況下,編譯器將能夠檢查通過 arguments 到 function。 而且 function strcaT
的名稱令人困惑。 至少 function 可以命名為strCat
。
function 可以通過以下方式定義
#include <stdio.h>
#include <string.h>
char * strCat( char *s1, const char *s2 )
{
char *p = s1 + strlen( s1 );
while ( ( *p++ = *s2++ ) );
return s1;
}
int main(void)
{
enum { N = 14 };
char s1[N] = "first";
char *s2 = "second";
puts( strCat( s1, s2 ) );
return 0;
}
程序 output 是
firstsecond
On the other hand if you are already using the standard C function strlen
then why not to use another standard C function strcpy
?
有了這個 function 你的 function 可以定義得更簡單,比如
char * strCat( char *s1, const char *s2 )
{
strcpy( s1 + strlen( s1 ), s2 );
return s1;
}
如果您想構建一個新的字符數組,其中包含兩個附加到另一個的字符串,那么 function 可以通過以下方式查找。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * strCat( const char *s1, const char *s2 )
{
size_t n1 = strlen( s1 );
char *result = malloc( n1 + strlen( s2 ) + 1 );
if ( result != NULL )
{
strcpy( result, s1 );
strcpy( result + n1, s2 );
}
return result;
}
int main(void)
{
char *s1 = "first";
char *s2 = "second";
char *result = strCat( s1, s2 );
if ( result ) puts( result );
free( result );
return 0;
}
再次,程序 output 是
firstsecond
當然,標准 C function strcpy
的調用可以替代您自己的循環,但這沒有多大意義。
如果不允許使用標准的 C 字符串函數,那么上面的 function 可以通過以下方式實現。
#include <stdio.h>
#include <stdlib.h>
char * strCat( const char *s1, const char *s2 )
{
size_t n = 0;
while ( s1[n] != '\0' ) ++n;
for ( size_t i = 0; s2[i] != '\0'; )
{
n += ++i;
}
char *result = malloc( n + 1 );
if ( result != NULL )
{
char *p = result;
while ( ( *p = *s1++ ) != '\0' ) ++p;
while ( ( *p = *s2++ ) != '\0' ) ++p;
}
return result;
}
int main(void)
{
char *s1 = "first";
char *s2 = "second";
char *result = strCat( s1, s2 );
if ( result ) puts( result );
free( result );
return 0;
}
中主function
char *strcaT();
應該在main
function之前聲明:
char *strcaT(char *t, char *s);
int main() {...}
您返回本地數組buffer[]
,這是未定義的行為,因為在strcaT
function 之外,它可能不存在。 您應該使用指針然后為其分配。
buffer
的大小應該是+1
而不是-1
,就像你在代碼中所做的那樣。
char *strcaT(char *t, char *s) {
char *a = malloc(strlen(t) + strlen(s) + 1);
if (!a) {
return NULL;
}
int i;
for(i = 0; t[i] != '\0'; i++) {
a[i] = t[i];
}
for(int j = 0; s[j] != '\0'; j++,i++) {
a[i] = s[j];
}
a[i] = '\0';
return a;
}
完整的測試代碼:
#include <stdio.h>
#include <stdlib.h>
char *strcaT(char *t, char *s);
int main() {
char *a = "first";
char *b = "second";
char *str = strcaT(a, b);
if (str != NULL) {
printf("%s\n", str);
free(str); // Never forget freeing the pointer to avoid the memory leak
}
return 0;
}
char *strcaT(char *t, char *s) {
char *a = malloc(strlen(t) + strlen(s) + 1);
if (!a) {
return NULL;
}
int i;
for(i = 0; t[i] != '\0'; i++) {
a[i] = t[i];
}
for(int j = 0; s[j] != '\0'; j++,i++) {
a[i] = s[j];
}
a[i] = '\0';
return a;
}
我已將您的程序更改為如下所示:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char* strcaT();
char* a = "first";
char* b = "second";
printf("%s",strcaT(a,b));
return 0;
}
char* strcaT(char *t, char *s)
{
char* a = (char*)malloc(sizeof(char)*(strlen(t) + strlen(s) + 1));
for(int i=0; i<strlen(t); i++) {
a[i] = t[i];
}
for(int i=0; i<strlen(s); i++) {
a[strlen(t) + i] = s[i];
}
a[strlen(t)+strlen(s)] = '\0';
return a;
}
您正在收到段錯誤,因為您正在返回堆棧上的本地數組的地址,並且在您返回后將無法訪問。 其次是您的邏輯連接字符串很復雜。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.