【问题标题】:Program: String concatenation using concept of variable arugment functions程序:使用可变参数函数概念的字符串连接
【发布时间】:2017-05-15 13:23:42
【问题描述】:

您好,我是初学者,我正在使用可变参数函数的概念来连接字符串。不同数量的字符串调用相同的函数。

我无法计算连接字符串的长度,这反过来意味着我没有正确分配内存。亲爱的同行,请帮忙!

/* Program to do string concatenation using the concept of variable arguments */

/********************************************************************************
*                               REQUIRED HEADER FILES
*********************************************************************************/

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

/********************************************************************************
*                               REQUIRED MACROS DEFINED
*********************************************************************************/

#define ERROR_CHECKER(result)\
    if(result == FAILURE)\
    {\
        printf("\n CONCATENATION FAILED");\
    }
typedef enum {SUCCESS = 0, FAILURE = 1} return_type;

/********************************************************************************
*                               REQUIRED FUNCTION PROTOTYPES
*********************************************************************************/
return_type string_concat(char* string_pointer, ...);

/********************************************************************************
*
*    FUNCTION_NAME  :  STRING_CONCAT
*
*    DESCRIPTION    :  concatenates incoming strings and displays the result
*
*    RETURNS        :  SUCCESS OR FAILURE 
*
*********************************************************************************/
return_type string_concat(
    char* string_pointer, 
    ...)
{

/********************************************************************************
*                               REQUIRED DECLARATIONS
*********************************************************************************/
// 1. arg_list that will point to variable number of arguments 
va_list arg_list;

// 2. pointer to concatenated string 
char* concatenated_string;

// 3. character pointer to point to an individual element in the argument list
char* individual_string_pointer;

// 4. amount of memory required to be allocated 
int length;
/*********************************************************************************
*                               REQUIRED INITIALIZATIONS
*********************************************************************************/
va_start(arg_list, string_pointer);
concatenated_string = NULL;
individual_string_pointer = string_pointer;
length = 0;
/*********************************************************************************
*                               PERFORMING REQUIRED TASKS
**********************************************************************************/

// 1. calculate length till you reach quit
while(strcmp(individual_string_pointer,"quit") == 0)
{
    individual_string_pointer = va_arg(arg_list, char*);
    length = length + strlen(individual_string_pointer);
}

// individual_string_pointer reinitialized to be used for concatenation
individual_string_pointer = string_pointer;

printf("\nlength of concatenated string : %d", length);

// 2. allocate memory for the concatenated string
concatenated_string = (char*) malloc(sizeof(char) * length + 1);

// 3. use strncpy to copy first string and then use strncat to concatenate others

strncpy(concatenated_string, string_pointer, sizeof(*(string_pointer)));

while(strcmp(individual_string_pointer, "quit") == 0)
{
    individual_string_pointer = va_arg(arg_list, char*);
    strncat(concatenated_string, individual_string_pointer, sizeof(*(individual_string_pointer)));
}

printf("\n concatenated string : %s",concatenated_string);

va_end(arg_list);
return SUCCESS;
}

/********************************************************************************
*
*   FUNCTION_NAME   :   MAIN
*
*   DESCRIPTION     :   CALLS STRING_CONCAT FUNCTION
*
*   RETURNS         : SUCCESS 
*********************************************************************************/
int main(void)
{

/********************************************************************************
*                               REQUIRED DECLARATIONS
*********************************************************************************/
// 1. character array as the first argument
char string_one[5] = "hello" ;

// 2. variable to store result from the string_concat function.
int result;

/*********************************************************************************
*                               REQUIRED INITIALIZATIONS
**********************************************************************************/

result = 0;

/*********************************************************************************
*                               PERFORMING REQUIRED TASKS
**********************************************************************************/
// 1. call string_concat function with 2 arguments
   result = string_concat(string_one, "my", "name","is","amninder","quit");
    // handle error from string_concat
    ERROR_CHECKER(result);

// 2. call string_concat function with 3 arguments
   result = string_concat(string_one, "I", "Like","fruits","quit");
    // handle error from string_concat
    ERROR_CHECKER(result);  

// 3. call string_concat function with 4 arguments 
   result = string_concat(string_one, "awesome","quit");
    // handle error from string_concat
    ERROR_CHECKER(result);
/* doubt: do I need to send my first argument as same always " */
return SUCCESS;
}

【问题讨论】:

  • 无需使用strn*() 版本。
  • string_one[5] --> string_one[6]
  • 你不能使用同一个 va_list 两次:stackoverflow.com/questions/9309246/…
  • while(strcmp(individual_string_pointer,"quit") != 0) 很好奇。为什么"quit"?建议改为const * const quit = NULL; ... string_concatresult = string_concat(string_one, "my", "name","is","amninder", quit); ... while(individual_string_pointer != quit)
  • 大幅更改代码不符合 SO 标准。就像现在的代码一样,1 答案没有意义。建议恢复到以前的编辑。

标签: c string concatenation


【解决方案1】:

除了其他问题:这个sizeof(*(individual_string_pointer)));返回individual_string_pointer指向的大小,即char,所以它返回1。

要么改用strlen(ndividual_string_pointer),要么改用strcat(),如下所示:

strcat(concatenated_string, individual_string_pointer)

【讨论】:

  • 现在我可以打印我的两个字符串 - 我已经使用了上面指出的两件事 1. 使用 va_list 两次将不起作用,因此使用 va_list 类型创建了两个 arg_lists 即 arg_list 和 arg_list2 2. 现在使用strlen(individual_string_pointer) 而不是 sizeof()。非常感谢。
  • 程序仍然在第三个字符串处崩溃..我每次都在释放内存仍然不知道为什么会这样......已经更新了我上面的代码
  • phew.. 终于搞定了... 实际上这里的内存分配有问题 - while(strcmp(individual_string_pointer,"quit") != 0) { length = length + strlen(individual_string_pointer) ; /* 第 1 行 / individual_string_pointer = va_arg(arg_list, char); /* 第 2 行 */ } 实际上我把第 2 行放在第 1 行之前...谢谢大家...
  • @Amninder:请注意,“不能使用va_list 两次”的内容并不完全准确(礼貌)。
  • @JonathanLeffler 嗯.. 我现在知道了.. 使用 2 个 va_list 变量来完成任务。现在只是看到其他人接近..
【解决方案2】:

您的方法还不错,但可以改进,“退出”标记 va_list 的结尾不是很安全,NULL 是更好的选择。因为用户可能会在“quit”中出现错误,如“qui”、“qit”或其他。以及如何连接“退出”?如果您在不知道函数内部内容的情况下使用string_concat,则当其中一个字符串为“退出”时可能会提前停止:

char *string1 = "foo";
char *string2 = "quit";
char *string3 = "bar";
string_concat(string1, string2, string3, "quit");

只会使用“foo”。

你不返回字符串 generate 所以你的函数不是真的有用。

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

#define END_STRING_CONCAT ((char const *)NULL)

char *string_concat(char const *first, ...);

char *string_concat(char const *first, ...) {
  va_list ap;
  va_start(ap, first);

  va_list cp_ap;
  va_copy(cp_ap, ap); // copy for future use

  size_t size = 1; // need the size of the future string
  for (char const *ptr = first; ptr != NULL; ptr = va_arg(ap, char const *)) {
    size += strlen(ptr);
  }
  va_end(ap);

  char *result = malloc(size);
  if (result == NULL) {
    va_end(cp_ap);
    return NULL;
  }

  size_t used = 0;
  for (char const *ptr = first; ptr != NULL; ptr = va_arg(cp_ap, char const *)) {
    size_t len = strlen(ptr);
    if (size < used || size - used < len) {
      free(result);
      va_end(cp_ap);
      return NULL;
    }
    memcpy(result + used, ptr, len); // use memcpy because it's faster in this case
    used += len;
  }
  va_end(cp_ap);
  if (size < used || size - used != 1) {
    free(result);
    return NULL;
  }
  result[used] = '\0'; // don't forget

  return result;
}

int main(void) {
  char hello[] = "hello, ";

  char *result1 = string_concat(hello, "my ", "name ", "is ", "amninder",
                                END_STRING_CONCAT);
  if (result1 != NULL) {
    printf("%s\n", result1);
    free(result1);
  }

  char *result2 = string_concat(hello, "I ", "Like ", "fruits", END_STRING_CONCAT);
  if (result2 != NULL) {
    printf("%s\n", result2);
    free(result2);
  }

  char *result3 = string_concat(hello, "awesome", END_STRING_CONCAT);
  if (result3 != NULL) {
    printf("%s\n", result3);
    free(result3);
  }

  return 0;
}

【讨论】:

  • NULL 不是便携更好的选择。 NULL 未定义为指针类型,更不用说 char *NULL 可以是 int,例如 0。将NULL 传递给... 参数并不能保证NULL 被转换为空指针。所以va_arg(ap, char *) 可能作用于int,这可能与char* 不同 - 生成的UB。需要的是一个指定char *的常量,如commented
  • @chux 你确定吗?因为 C99 将 NULL 定义为“扩展为实现定义的空指针常量”。 Can a conforming C implementation #define NULL to be something wacky,我不明白 NULL 是指向 void 的指针。不管NULL 不是void 指针。将其转换为char * 是没有用的,不是吗?它会产生其他未定义的行为,因为只有 void *char * 可以转换为其他类型的指针,不是吗?
  • 谢谢 chux... 但从现在开始我将使用 memcpy() 而不是 strncpy() 因为它更快.. 所以谢谢你们... 这样的讨论提高了我的学习..: ) 再次感谢..
  • "对我来说 NULL 是一个指向 void 的指针" --> C 规范没有指定。 NULL 可以简单地扩展为 0,即 int。 “NULL 扩展为实现定义的空指针常量。” (§7.19 3)。 空指针常量(可能不止1个)不一定是指针,听起来很奇怪。 “如果将空指针常量转换为指针类型,则生成的指针,称为 空指针” §6.3.2.3 3.
  • "把它转换成 char * 没用" --> 很有用。传递给string_concat(..., (char *) NULL) 的值和类型然后匹配使用va_arg(cp_ap, char *) 提取的类型,并与ptr != NULL 进行比较。
【解决方案3】:

与其迭代va_list 两次,不如考虑realloc() 并附加每个子字符串。 cmets 中的其他想法。

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

#define return_type int
#define FAILURE -1
#define SUCCESS 0

//                        use const 
return_type string_concat(const char* string_pointer, ...) {
  va_list arg_list;
  va_start(arg_list, string_pointer);

  char* concatenated_string = NULL;
  size_t length = 0;  // Use type size_t, not int
  const char* individual_string_pointer = string_pointer;

  while (strcmp(individual_string_pointer, "quit")) {
    // Find sub-string length _once_
    size_t individual_length = strlen(individual_string_pointer);
    size_t new_length = length + individual_length;
    char *new_ptr = realloc(concatenated_string, new_length + 1);
    if (new_ptr == NULL) {
      free(concatenated_string);  // do not forget to free old string
      printf("\n MALLOC FALIED");
      return FAILURE;
    }

    concatenated_string = new_ptr;

    // or use memcpy(concatenated_string + length, 
    //            individual_string_pointer, individual_length+1)
    strcpy(concatenated_string + length, individual_string_pointer);

    length = new_length;

    individual_string_pointer = va_arg(arg_list, const char*);
  }
  va_end(arg_list);

  // Add <> to detect leading/trailing white-space
  printf("Concatenated string : <%s>\n", concatenated_string);
  free(concatenated_string);
  return SUCCESS;
}

int main(void) {
  //        not [5], let compiler size it to include the null character
  char string_one[] = "hello";
  string_concat(string_one, "my", "name", "is", "amninder", "quit");
  string_concat(string_one, "I", "Like", "fruits", "quit");
  return 0;
}

输出

Concatenated string : <hellomynameisamninder>
Concatenated string : <helloILikefruits>

【讨论】:

  • 我会说迭代两次比使用 realloc 好得多。
  • @hyde 只是提供选项,因为 OP 在 2 次传球时遇到了麻烦,我想va_list。当然你也可以发布你更好的想法。
  • 我也这么认为...在循环中使用 realloc() 会导致内存碎片,但非常感谢您的洞察力..
  • 是的,可以考虑使用realloc,但在这种情况下,考虑的结果应该是“我可以很容易地找出所需的总分配,所以我应该只做一个分配而不是使用realloc。”如果在循环中使用realloc,它可能应该与呈指数增长的分配大小一起使用,以限制最大重新分配的数量。
  • @hyde 单次传递(重复realloc())的另一个好处是每个子字符串不会调用strlen() 两次。 IOWs,各种方法的整体影响需要分析而不是分析部分。为了性能,我会使用一个固定大小的字符串指针/长度对数组来处理 99% 的调用将少于 N 个参数(比如 16 或 32) - 然后分配缓冲区。额外的代码将处理病态的众多论点。同意使用指数增长分配一个好主意,
【解决方案4】:

您的第一个问题是您没有对数据做任何事情。你的第二个是一个烦人的规则,防止两次迭代参数列表。

将连接的字符串作为分配的内存返回,如果失败则返回 0

char *concat(const char *first, ...)
{
    char *answer;
    int lenght;
    va_list va;
    char *nest;
    int nextlen;

    length = strlen(first);
    answer = malloc(length + 1);
    if(!answer)
       goto out_of_memory;
    strcpy(first, answer);

    va_start(va, &first);
    do
    {
        next = va_arg(va, char *);
        if(!strcpy(nest, "quit))
          break;
        nextlen = strlen(next);
        temp = realloc(answer, length + nextlen+1);
        if(!temp)
           goto out_of_memory;
        answer = temp;
        strcpy(answer, next);
        length += nextlen;
    } while(1);
    va_end(va);

    return answer;
    out_of_memory:
      free(answer);
      return 0;
}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2022-10-21
  • 2014-03-15
  • 2014-12-18
  • 2019-07-24
  • 2018-11-18
  • 1970-01-01
  • 2019-11-23
  • 1970-01-01
相关资源
最近更新 更多