【问题标题】:Why does this C program not function properly?为什么这个 C 程序不能正常运行?
【发布时间】:2016-02-22 22:58:18
【问题描述】:

此 C 程序将字符串“1 2 3 4 5 6 7 8 9 10”拆分为标记,将它们存储在buf 中,并打印buf 的内容。

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

/* Fills an array with pointers to the tokens of the given string.
 * string: A null-terminated char*
 * buf: A buffer to be filled with pointers to each token. 
 */
void get_tokens(char * string, char ** buf) {
    char tmp[100];
    strncpy(tmp, string, 100);
    char * tok = strtok(tmp, " \n");
    int i = 0;
    while (tok != NULL) {
        buf[i] = tok;
        tok = strtok(NULL, " \n");
        i++;
    }
}

int main() {
    char ** buf = malloc(10 * sizeof(char*));
    char * string = "1 2 3 4 5 6 7 8 9 10";
    get_tokens(string, buf);

    int i;
    for (i = 0; i < 10; i++) {
        printf("  %s\n", buf[i]);
    }
}

输出:

  1
  2
  3
  4
   s�c8
  �c8
  8

  9
  10

为什么我的输出被破坏了?

【问题讨论】:

  • 根本原因是tmpget_tokens返回后超出范围。
  • char tmp[100]; 是局部变量。该部分的地址超出范围无效。
  • 但是strtok返回的指针不是指向tmp的指针,是malloc组成的独立字符串
  • “它们是用 malloc 制作的独立字符串”。真的吗?代码的哪一部分是这样做的? char * tok = strtok(tmp, " \n"); buf[i] = tok;tok 指向tmp 中的一个位置。
  • 我想我现在明白了,谢谢。 strtok 的输入字符串被破坏的原因是 strtok 只是将分隔符替换为 \0 并返回一个指向每个标记 within tmp 开头的指针。

标签: c arrays memory malloc declaration


【解决方案1】:

数组tmp是具有自动存储时长的函数的本地数组。它在函数退出后被销毁。所以所有指向数组元素的指针都会失效。

我可以建议以下解决方案

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

size_t get_tokens( char ** buf, size_t n, const char *string ) 
{
    char tmp[100];
    strncpy( tmp, string, 100 );
    tmp[99] = '\0';

    size_t i = 0;
    char * tok = strtok( tmp, " " );

    while ( i < n && tok != NULL ) 
    {
        buf[i] = malloc( strlen( tok ) + 1 );
        strcpy( buf[i++], tok );
        tok = strtok( NULL, " " );
    }

    return i;
}

int main( void ) 
{
    const size_t N = 10;

    char ** buf = malloc( N * sizeof( char * ) );
    char * string = "1 2 3 4 5 6 7 8 9 10";

    size_t n = get_tokens( buf, N, string );

    for ( size_t i = 0; i < n; i++ ) 
    {
        puts( buf[i] );
    }

    for ( size_t i = 0; i < n; i++ ) free( buf[i] );
    free( buf );

    return 0;
}

程序输出是

1
2
3
4
5
6
7
8
9
10

至于您的程序,那么至少您应该使用存储说明符static 声明数组。

例如

static char tmp[100];
^^^^^^
strncpy( tmp, string, 100 );
tmp[99] = '\0';
^^^^^^^^^^^^^^^

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-19
    • 1970-01-01
    • 2012-11-11
    • 1970-01-01
    • 2013-09-28
    • 1970-01-01
    • 1970-01-01
    • 2021-08-22
    相关资源
    最近更新 更多