C语言 将argv[]中的所有字符串连接在一起

wyyhbhjk  于 2023-02-03  发布在  其他
关注(0)|答案(2)|浏览(160)
#include <cs50.h>
#include <stdio.h>
#include <string.h>

int main(int argc, string argv[])
{
    string destination = argv[1];

    for (int i = 1; i < argc; i++)
    {
        strcat(argv[i], argv[i+1]);
    }
    printf("%s\n", destination);
}

我需要所有的字符串在argv[ ]连接在一起。下面的程序工作,但在年底给予seg错误(核心转储)。我如何才能避免?

p3rjfoxz

p3rjfoxz1#

CS50被认为是有害的。C语言中没有字符串类,与大多数其他语言相比,它是一种低级语言。没有自动内存管理。你必须手动推出所有内容。
argv[n]恰好是一个允许写入的位置,但这样做是不好的做法,该位置的空间只够存储已经传递的参数字符串,因此不能在那里追加任何内容。
您需要使用的算法如下:

  • 对传递的参数的所有字符串长度求和。例如:
size_t argv_strlen [argc];
size_t total_size=0;
for (size_t i=1; i<argc; i++)
{
  argv_strlen[i] = strlen(argv[i]);
  total_size += argv_strlen[i];
}
total_size += 1; // make room for null termination
  • 分配足够的内存来保存连接的字符串。例如:
#include <stdlib.h>
...
char* new_str = malloc (total_size);
if(new_str == NULL)
{ /* no memory available, handle error */ }
  • 将字符串一个接一个地复制到分配的空间中。这可以通过几种方式来完成。

简单但对初学者友好的版本是使用strcat(string.h),它连接字符串,为了使用它,使用的第一项必须是以空结尾的字符串,所以它是这样的:

// make sure the first item is a null terminator:
*new_str = '\0';
/* new_str is now an empty string but with sufficient 
   space available behind the null terminator */

for(size_t i=1; i<argc; i++)
{
  strcat(new_str, argv[i]);
}

但是strcat需要一遍又一遍地寻找空值结束符,所以这是非常慢的。更专业的版本是保存我们之前获取的字符串长度(啊哈,这就是argv_strlen数组的作用),然后使用memcpy(string.h)复制这么多内存+1个字节用于空值结束符,这比strcat快得多。

char* copy_here = new_str; // temporary pointer to keep track of where to copy
for(size_t i=1; i<argc; i++)
{
  memcpy(copy_here, argv[i], argv_strlen[i]+1);

  // point at the next null terminator, then overwrite it the next iteration:
  copy_here += argv_strlen[i]; 
}

完整示例:

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

int main(int argc, char* argv[])
{
  if(argc <= 1)
  {
    // print some error message here
    return 0;
  }
  
  size_t argv_strlen [argc];
  size_t total_size=0;
  for (size_t i=1; i<argc; i++)
  {
    argv_strlen[i] = strlen(argv[i]);
    total_size += argv_strlen[i];
  }
  total_size += 1; // make room for null termination

  char* new_str = malloc (total_size);
  if(new_str == NULL)
  {
    // print some error message here
    return 0;
  }

  char* copy_here = new_str;
  for(size_t i=1; i<argc; i++)
  {
    memcpy(copy_here, argv[i], argv_strlen[i]+1);
    copy_here += argv_strlen[i];
  }

  puts(new_str);
  free(new_str);
}

命令行输入progname hello world how are you?给出helloworldhowareyou?

ljsrvy3e

ljsrvy3e2#

argv[i]都没有足够的空间来存储附加的字符串(当然,如果附加的字符串不是空字符串)。
此外,argv[argc]是一个空指针。

strcat(argv[i], argv[i+1]);

i等于argc-1时使用空指针argv[i+1],这再次导致未定义的行为。
来自C标准(5.1.2.2.1程序启动)
argv[argc]应为空指针
至少你应该写

strcat(destination, argv[i]);

代替

strcat(argv[i], argv[i+1]);

假设数组destination可以包含所有连接的字符串。
您需要动态分配一个足够大的数组,以便能够存储所有连接的字符串。
例如

size_t length = 0;

for ( int i = 1; i < argc; i++ )
{
    length += strlen( argv[i] );
}

char *s = malloc( length + 1 );

if ( s )
{
    *s = '\0';

    for ( int i = 1; i < argc; i++ )
    {
        strcat( s, argv[i] );
    }

    puts( s );
}

free( s );

或者当您使用类型别名string作为类型char *时,则将

char *s = malloc( length + 1 );

你可以写

string s = malloc( length + 1 );

相关问题