为什么我在 c 中的自定义串联函数得到错误的结果?
Why I get wrong result for custom concatenation function in c?
我正在开发一个自定义连接函数(它是我的拼贴画的一项任务),但我无法让它工作,当我打印连接结果时,我得到了奇怪的字符。
这是我的代码
typedef struct {
int len;
char *s;
} string_t;
typedef string_t* string;
void set (string* s1, char *s);
void concat (string* s1, string s2);
int main(void) {
//create variables
string *str1;
string *str2;
set(str1,"hello ");
set(str2,"world!");
printf("\nconcatenate str1 and str2\n");
concat(str1,*str2);
printf("concatenation result is:\n");
//the problem is here
printf("%p , %s",(*str1)->s,(*str1)->s);
printf("\n------End------\n");
return EXIT_SUCCESS;
}
void set(string* s1, char *s){
if(s1 != NULL){
if(s == NULL){
(*s1)->len = -1;
}else{
(*s1)->s = s;
(*s1)->len = strlen(s);
}
}
}
void concat (string* s1, string s2){
int totalLen = (*s1)->len + (*s2).len;
char rslt[totalLen+1];
int i=0;
for(i=0;i<(*s1)->len;i++){
rslt[i] = (*s1)->s[i];
}
for(i=(*s1)->len;i<totalLen;i++){
int j=i-(*s1)->len;
rslt[i] = (*s2).s[j];
}
rslt[totalLen] = '[=10=]';
set(s1,rslt);
//there is no problem when printing here
printf("%p , %s\n",(*s1)->s,(*s1)->s);
}
这是我得到的结果
连接 str1 和 str2
0023FE2C,世界,你好!
连接结果为:
0023FE2C, ì@@
------结束------
我正在使用 Eclipse IDE。
谁能帮我解决这个问题?
您的 concat
函数 returns 指向本地数组 rslt
的指针。该数组仅在调用封闭函数期间有效。 concat
退出后 str1->s
包含 dangling pointer。使用它会导致未定义的行为。
解决此问题的一种方法是将此数组复制到堆分配的内存中:
void set(string* s1, const char *s){
free(s1->s);
s1->s = strdup(s);
s1->len = strlen(s);
}
修复示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int len;
char *s;
} string;
//typedef string_t string;//no need pointer type.
void set (string *s1, const char *s);
void concat (string *s1, const string *s2);//Unified to pointer
string *create(const char *s);
int main(void) {
string *str1 = create(NULL);//calloc(1, sizeof(*str1));//create("");//create("hello ");
string *str2 = create(NULL);//calloc(1, sizeof(*str2));//create("");
set(str1, "hello ");
set(str2, "world!");
printf("\nconcatenate str1 and str2\n");
concat(str1, str2);
printf("concatenation result is:\n");
printf("%s", str1->s);
printf("\n------End------\n");
free(str1->s);free(str1);
free(str2->s);free(str2);
return EXIT_SUCCESS;
}
string *create(const char *s){
string *str = malloc(sizeof(*str));
if(str){
if(s){
str->len = strlen(s);
str->s = strdup(s);//strdup isn't standard
/*
str->s = malloc(str->len + 1);
if(!str->s){
free(str);
str = NULL;
} else {
memcpy(str->s, s, str->len + 1);
}
*/
} else {
str->len = -1;
str->s = NULL;
}
}
return str;
}
void set(string *s1, const char *s){
if(s1 != NULL){
free(s1->s);
if(s == NULL){
s1->s = NULL;
s1->len = -1;
}else{
s1->s = strdup(s);
s1->len = strlen(s);
}
}
}
void concat (string *s1, const string *s2){
if(!s1 || !s2 || s1->len == -1 || s2->len == -1)
return ;
int totalLen = s1->len + s2->len;
char rslt[totalLen+1];//char *rslt = malloc(totalLen+1);
strcpy(rslt, s1->s);//use standard library
memcpy(rslt + s1->len, s2->s, s2->len + 1);
set(s1, rslt);
//free(rslt);
}
// code readability is every bit as important as the algorithm used
// when compiling, have all warnings enabled, and then fix them
// OP can add parameter checking and make the str1 and str1 be pointers
// with appropriate changes to the rest of the code
// I changed return types from void to int
// for set() and concat() so main could free the allocated memory areas
// the 'software contract' concept says the sub functions in the file
// do not need to check their parameters for validity
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // strlen()
// strdup() should have been prototyped by string.h,
// but was not on my computer
char *strdup(const char *s);
// dont clutter the code with frivilous typedef's
struct string_t
{
int len;
char * s;
};
// prototypes
int concat (struct string_t*, struct string_t* );
int set( struct string_t*, char* );
int main(void)
{
//create variables
// your learning C, so keep it simple
struct string_t str1 = {0,NULL}; // good programming practice to initialize local variables
struct string_t str2 = {0,NULL};
if( !set( &str1, "hello " ) )
{
if( !set( &str2, "world!" ) )
{
printf("\nconcatenate str1 and str2\n");
if( !concat(&str1,&str2) )
{
printf("concatenation result is:\n");
printf("%p , %s",(void*)&(str1.s), str1.s);
printf("\n------End------\n");
} // end if
} // end if
} // end if
free(str1.s);
free(str2.s);
return EXIT_SUCCESS;
} // end function: main
// <-- pString1 must point to an instance of struct string_t
// do not free() the pNewString
// as it is a pointer to a literal,
// not a pointer to allocated memory
int set( struct string_t* pString1, char* pNewString ) // <-- use meaningful/descriptive names
{
int returnValue = 0; // indicate success
char * temp = strdup(pNewString);
if( NULL == temp )
{ // then strdup failed
perror( "strdup failed" );
returnValue = 1; // indicate failure
}
else
{ // else, strdup successful
pString1->s = temp;
pString1->len = strlen(pString1->s)+1;
}
return( returnValue );
} // end function: set
int concat (struct string_t* pString1, struct string_t* pString2)
{
int returnValue = 0; // indicate success
int totalLen = pString1->len + pString2->len + 1;
//printf( "\nbefore: string1->len =%i,string2->len=%d, totalLength=%i\n",
// pString1->len,
// pString2->len,
// totalLen);
//printf("\nbefore: string1:%s, string2:%s\n",
// pString1->s, pString2->s);
// <-- there is no room in string1->s for any more chars so:
char * temp;
if( NULL == (temp = realloc(pString1->s, totalLen) ) )
{ // then realloc failed
perror( "realloc failed" );
returnValue = 1; // indicate failure
}
else
{
free( pString1->s);
pString1->s = temp;
//printf("\n after realloc: str1.len:%i, strl.s:%s\n",
// pString1->len, pString1->s);
int i=0;
for(;i<totalLen;i++)
{
pString1->s[strlen(pString1->s)] = pString2->s[i];
pString1->s[strlen(pString1->s)] = '[=10=]';
} // end for
pString1->len = totalLen;
pString1->s[totalLen] = '[=10=]';
//printf("after: str1addr:%p , str1:%s\n",pString1->s,pString1->s);
//printf( "\nstring1->len =%i,string2->len=%d, totalLength=%i\n",
// pString1->len,
// pString2->len,
// totalLen);
} // end if
return( returnValue );
} // end function: concat
我正在开发一个自定义连接函数(它是我的拼贴画的一项任务),但我无法让它工作,当我打印连接结果时,我得到了奇怪的字符。
这是我的代码
typedef struct {
int len;
char *s;
} string_t;
typedef string_t* string;
void set (string* s1, char *s);
void concat (string* s1, string s2);
int main(void) {
//create variables
string *str1;
string *str2;
set(str1,"hello ");
set(str2,"world!");
printf("\nconcatenate str1 and str2\n");
concat(str1,*str2);
printf("concatenation result is:\n");
//the problem is here
printf("%p , %s",(*str1)->s,(*str1)->s);
printf("\n------End------\n");
return EXIT_SUCCESS;
}
void set(string* s1, char *s){
if(s1 != NULL){
if(s == NULL){
(*s1)->len = -1;
}else{
(*s1)->s = s;
(*s1)->len = strlen(s);
}
}
}
void concat (string* s1, string s2){
int totalLen = (*s1)->len + (*s2).len;
char rslt[totalLen+1];
int i=0;
for(i=0;i<(*s1)->len;i++){
rslt[i] = (*s1)->s[i];
}
for(i=(*s1)->len;i<totalLen;i++){
int j=i-(*s1)->len;
rslt[i] = (*s2).s[j];
}
rslt[totalLen] = '[=10=]';
set(s1,rslt);
//there is no problem when printing here
printf("%p , %s\n",(*s1)->s,(*s1)->s);
}
这是我得到的结果
连接 str1 和 str2
0023FE2C,世界,你好!
连接结果为:
0023FE2C, ì@@
------结束------
我正在使用 Eclipse IDE。
谁能帮我解决这个问题?
您的 concat
函数 returns 指向本地数组 rslt
的指针。该数组仅在调用封闭函数期间有效。 concat
退出后 str1->s
包含 dangling pointer。使用它会导致未定义的行为。
解决此问题的一种方法是将此数组复制到堆分配的内存中:
void set(string* s1, const char *s){
free(s1->s);
s1->s = strdup(s);
s1->len = strlen(s);
}
修复示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int len;
char *s;
} string;
//typedef string_t string;//no need pointer type.
void set (string *s1, const char *s);
void concat (string *s1, const string *s2);//Unified to pointer
string *create(const char *s);
int main(void) {
string *str1 = create(NULL);//calloc(1, sizeof(*str1));//create("");//create("hello ");
string *str2 = create(NULL);//calloc(1, sizeof(*str2));//create("");
set(str1, "hello ");
set(str2, "world!");
printf("\nconcatenate str1 and str2\n");
concat(str1, str2);
printf("concatenation result is:\n");
printf("%s", str1->s);
printf("\n------End------\n");
free(str1->s);free(str1);
free(str2->s);free(str2);
return EXIT_SUCCESS;
}
string *create(const char *s){
string *str = malloc(sizeof(*str));
if(str){
if(s){
str->len = strlen(s);
str->s = strdup(s);//strdup isn't standard
/*
str->s = malloc(str->len + 1);
if(!str->s){
free(str);
str = NULL;
} else {
memcpy(str->s, s, str->len + 1);
}
*/
} else {
str->len = -1;
str->s = NULL;
}
}
return str;
}
void set(string *s1, const char *s){
if(s1 != NULL){
free(s1->s);
if(s == NULL){
s1->s = NULL;
s1->len = -1;
}else{
s1->s = strdup(s);
s1->len = strlen(s);
}
}
}
void concat (string *s1, const string *s2){
if(!s1 || !s2 || s1->len == -1 || s2->len == -1)
return ;
int totalLen = s1->len + s2->len;
char rslt[totalLen+1];//char *rslt = malloc(totalLen+1);
strcpy(rslt, s1->s);//use standard library
memcpy(rslt + s1->len, s2->s, s2->len + 1);
set(s1, rslt);
//free(rslt);
}
// code readability is every bit as important as the algorithm used
// when compiling, have all warnings enabled, and then fix them
// OP can add parameter checking and make the str1 and str1 be pointers
// with appropriate changes to the rest of the code
// I changed return types from void to int
// for set() and concat() so main could free the allocated memory areas
// the 'software contract' concept says the sub functions in the file
// do not need to check their parameters for validity
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // strlen()
// strdup() should have been prototyped by string.h,
// but was not on my computer
char *strdup(const char *s);
// dont clutter the code with frivilous typedef's
struct string_t
{
int len;
char * s;
};
// prototypes
int concat (struct string_t*, struct string_t* );
int set( struct string_t*, char* );
int main(void)
{
//create variables
// your learning C, so keep it simple
struct string_t str1 = {0,NULL}; // good programming practice to initialize local variables
struct string_t str2 = {0,NULL};
if( !set( &str1, "hello " ) )
{
if( !set( &str2, "world!" ) )
{
printf("\nconcatenate str1 and str2\n");
if( !concat(&str1,&str2) )
{
printf("concatenation result is:\n");
printf("%p , %s",(void*)&(str1.s), str1.s);
printf("\n------End------\n");
} // end if
} // end if
} // end if
free(str1.s);
free(str2.s);
return EXIT_SUCCESS;
} // end function: main
// <-- pString1 must point to an instance of struct string_t
// do not free() the pNewString
// as it is a pointer to a literal,
// not a pointer to allocated memory
int set( struct string_t* pString1, char* pNewString ) // <-- use meaningful/descriptive names
{
int returnValue = 0; // indicate success
char * temp = strdup(pNewString);
if( NULL == temp )
{ // then strdup failed
perror( "strdup failed" );
returnValue = 1; // indicate failure
}
else
{ // else, strdup successful
pString1->s = temp;
pString1->len = strlen(pString1->s)+1;
}
return( returnValue );
} // end function: set
int concat (struct string_t* pString1, struct string_t* pString2)
{
int returnValue = 0; // indicate success
int totalLen = pString1->len + pString2->len + 1;
//printf( "\nbefore: string1->len =%i,string2->len=%d, totalLength=%i\n",
// pString1->len,
// pString2->len,
// totalLen);
//printf("\nbefore: string1:%s, string2:%s\n",
// pString1->s, pString2->s);
// <-- there is no room in string1->s for any more chars so:
char * temp;
if( NULL == (temp = realloc(pString1->s, totalLen) ) )
{ // then realloc failed
perror( "realloc failed" );
returnValue = 1; // indicate failure
}
else
{
free( pString1->s);
pString1->s = temp;
//printf("\n after realloc: str1.len:%i, strl.s:%s\n",
// pString1->len, pString1->s);
int i=0;
for(;i<totalLen;i++)
{
pString1->s[strlen(pString1->s)] = pString2->s[i];
pString1->s[strlen(pString1->s)] = '[=10=]';
} // end for
pString1->len = totalLen;
pString1->s[totalLen] = '[=10=]';
//printf("after: str1addr:%p , str1:%s\n",pString1->s,pString1->s);
//printf( "\nstring1->len =%i,string2->len=%d, totalLength=%i\n",
// pString1->len,
// pString2->len,
// totalLen);
} // end if
return( returnValue );
} // end function: concat