我怎样才能把一串数字拆分成C语言中的几个数字呢?

oalqel3c  于 2022-12-02  发布在  其他
关注(0)|答案(4)|浏览(166)

我想做两件事:

    • 1)**
char *myStr = "2 1 3 2 5 2 5 4 6 1 6 2 7 1 7 3 7 4 8 1 ";

我们的目标是让我的字符串是这样的

2 1
3 2 
5 2
...
...

依此类推,直到字符串结束。

    • 2)**对于这样的字符串,我想将这些值放入一个二维数组中,其形式为myArr [0][0]= 2,myArr [0][1]= 1,myArr [1][0]= 3,myArr [1][1]= 2,依此类推。

我首先尝试使用strtok,但我认为它不合适,因为分隔符不足以解决这个问题,然后通过逐字符迭代来拆分,但到目前为止,我不知道如何做到这一点:

const char * separator = " "
char * strToken = strtok ( out, separator );
while ( strToken != NULL ) {
  printf ( "%s\n", strToken);
  strToken = strtok ( NULL, separator);
}

我得到是:

2
1
3
2
5
2
5
4
6
1
6
2
7
1
7
3
7
4
8
1
dm7nw8vv

dm7nw8vv1#

在C语言中,试图把事情做得很小是很有诱惑力的,但是有时候把事情做得更长会更清楚。
在本例中,您尝试创建一个自定义解析器。有几种方法可以实现这一点,但复杂程度各不相同,但我将介绍一种简单的自顶向下方法,从输入字符串到整数值的二维数组。
你需要跟踪你扫描了字符串多远,以及你在2D数组中添加了什么。我假设这些是恒定长度的,如果需要的话,你可以把它们变成动态的。

char * myStrPtr = myStr;

int myArr[NUM_PAIRS][2];
int myArrIdx = 0;

基本的操作是扫描一个数字,然后跳过它后面的空格。这里有一个函数。它接受字符指针和一个指向整数的指针,然后返回一个指向下一个数字的指针(跳过错误检查)。

char * getInt(char * myStrPtr, int * i) {
    char *myEndPtr = NULL;
    *i = strtol(myStrPtr, &myEndPtr, 0);
    // Error if myEndPtr == myStrPtr. Skip spaces now.
    while (isspace(myEndPtr)) {
        myEndPtr++;
    }
    return myEndPtr;
}

你想一次扫描两个数字,这里有一个函数可以做到这一点。它接受字符指针,和一个一维int数组,并返回新的字符指针。

char * get2Ints(char * myStrPtr, int[2] intArr) {
    char *myEndPtr = NULL;

    // Skipping check for end of string.
    myEndPtr = getInt(myStrPtr, &intArr[0]);
    // Error if myEndPtr == myStrPtr, skipping that check.

    // Comments above apply here.
    myEndPtr = getInt(myStrPtr, &intArr[1]);

    return myEndPtr;
}

最后,你要扫描字符串中的所有对,我假设对的数量是已知的,否则你应该先计算它们的数量,然后为它们分配一个数组,或者使用链表来存储它们。

for (myArrIdx = 0; myArrIdx < NUM_PAIRS; myArrIdx++) {
    char * myEndPtr = get2Ints(myStrPtr, myArr[myArrIdx]);
    // Error if myArrPtr == myEndPtr.
    myStrPtr = myEndPtr;
}

这样就行了

ruyhziif

ruyhziif2#

有一种方法可以将数字存储在一维数组中,然后通过将它们转换为二维数组来显示它们。它不需要依赖于列数的存储过程。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NROW 10
#define NCOL 2
int main()
{
  char *myStr = "2 1 3 2 5 2 5 4 6 1 6 2 7 1 7 3 7 4 8 1 ";
  const char * separator = " ";
  char * strToken;
  char *out;
  char *end;
  /* 1D array */
  int arrBuf[NROW*NCOL];
  /* 2D array */
  int (*myArr)[NCOL] = (int(*)[NCOL])arrBuf;
  int i;
  out = strdup(myStr);
  /* Store numbers as 1D array */
  strToken = strtok ( out, separator );
  for (i = 0; i < NROW*NCOL && strToken != NULL ; i++) {
    arrBuf[i] = (int)strtol(strToken, &end, 10);
    strToken = strtok ( NULL, separator);
  }
  /* Display numbers as 2D array */
  for (i = 0; i < NROW; i++) {
    printf("%d %d\n", myArr[i][0], myArr[i][1]);
  }
  free(out);
  return 0;
}
olhwl3o2

olhwl3o23#

strtol解析内容。下面的代码非常脆弱,需要精确的输入,但它给出了大致的思路:

#include <ctype.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

int
main(void)
{
    char myStr[] = "2 1 3 2 5 2 5 4 6 1 6 2 7 1 7 3 7 4 8 1 ";
    int arr[10][2];
    char *t = myStr;
    int (*a)[2] = arr;
    while( t < myStr + sizeof myStr && *t ){
        char *end;
        a[0][0] = strtol(t, &end, 10);
        assert(isspace(*end));
        a[0][1] = strtol(end + 1, &end, 10);
        assert(isspace(*end));
        *end = '\n';
        t = end + 1;
        a += 1;
    }
    printf("%s", myStr);
    for( int i = 0; i < 10; i += 1 ){
        printf("%d, %d\n", arr[i][0], arr[i][1]);
    }
}
axr492tv

axr492tv4#

我首先尝试使用strtok,但我认为它不合适,因为分隔符不足以解决此问题
这不是使用strtok的问题。strtok的问题是它必须用空终止字符覆盖分隔符,这样单个字段就变成了以空字符终止的字符串。但是,myStr是指向string literal的指针,不允许修改。
因此,如果要使用strtok,必须将字符串文字复制到可写的内存缓冲区,或者不将myStr声明为指向字符串文字的指针,而是声明为可写的char数组,如下所示:

char myStr[] = "2 1 3 2 5 2 5 4 6 1 6 2 7 1 7 3 7 4 8 1 ";

以下是使用strtok的解决方案:

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

#define MAX_ROWS 100
#define COLS_PER_ROW 2

int main( void )
{
    char myStr[] = "2 1 3 2 5 2 5 4 6 1 6 2 7 1 7 3 7 4 8 1 ";
    const char delimiters[] = " ";
    char myArr[MAX_ROWS][COLS_PER_ROW];
    int num_rows = 0;
    char *p;

    //find first token
    p = strtok( myStr, delimiters );

    //process one row per loop iteration
    for (;;) //infinite loop, equivalent to while(1)
    {
        //process one column per loop iteration
        for ( int i = 0; i < COLS_PER_ROW; i++ )
        {
            //determine whether there are more tokens
            if ( p == NULL )
            {
                //print warning message if ran out of tokens in the
                //middle of a row, as this should only happen at the
                //start of a row
                if ( i != 0 )
                {
                    fprintf(
                        stderr,
                        "Warning: Ran out of tokens in the middle of "
                        "a row!\n"
                    );
                }

                //we cannot use "break" here, because that would
                //only break out of the innermost loop, but we must
                //break out of two levels of nested looops
                goto break_out_of_nested_loop;
            }

            //verify that we are not going to write to the array
            //out of bounds
            if ( num_rows == MAX_ROWS )
            {
                fprintf(
                    stderr,
                    "Too many rows to fit in the array! Stopping..."
                );

                goto break_out_of_nested_loop;
            }

            //print warning message and stop parsing if found token
            //is larger than one character
            if ( strlen( p ) > 1 )
            {
                fprintf(
                    stderr, 
                    "Warning: Found token is larger than "
                    "one character! Stopping...\n"
                );

                goto break_out_of_nested_loop;
            }

            //add found character to the array
            myArr[num_rows][i] = p[0];

            //find next token for next loop iteration
            p = strtok( NULL, delimiters );
        }

        //increase the number of valid rows in the array
        num_rows++;
    }

break_out_of_nested_loop:

    //print the content of the array
    for ( int i = 0; i < num_rows; i++ )
    {
        for ( int j = 0; j < COLS_PER_ROW; j++ )
        {
             printf( "%c ", myArr[i][j] );
        }

        printf( "\n" );
    }
}

此程序具有以下输出:

2 1 
3 2 
5 2 
5 4 
6 1 
6 2 
7 1 
7 3 
7 4 
8 1

请注意,如果可能的话,通常应该避免使用goto。但是,对于脱离嵌套循环,通常没有更好的选择,因此在这种情况下,通常认为它是可以接受的。
因为你只处理单个字符而不是字符串,所以你并不需要strtok。如果你不需要strtok,那么你也可以使用一个指向字符串的指针,就像你在问题中定义的那样:

char *myStr = "2 1 3 2 5 2 5 4 6 1 6 2 7 1 7 3 7 4 8 1 ";

下面是一个相应的解决方案:

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

#define MAX_ROWS 100
#define COLS_PER_ROW 2

int main( void )
{
    char *myStr = "2 1 3 2 5 2 5 4 6 1 6 2 7 1 7 3 7 4 8 1 ";
    char myArr[MAX_ROWS][COLS_PER_ROW];
    int num_rows = 0;
    char *p = myStr;

    //process one row per loop iteration
    for (;;) //infinite loop, equivalent to while(1)
    {
        //process one column per loop iteration
        for ( int i = 0; i < COLS_PER_ROW; i++ )
        {
            //skip all whitespace characters
            while ( isspace( (unsigned char)*p ) )
                p++;

            //determine whether next character is a digit
            if ( !isdigit( (unsigned char)*p ) )
            {
                //check if end of string is reached
                if ( *p != '\0' )
                {
                    //unexpected character was found, so print a
                    //warning message and stop parsing
                    fprintf(
                        stderr,
                        "Warning: Unexpected character found! "
                        "Stopping...\n"
                    );
                }

                //print warning message if ran out of digits in the
                //middle of a row, as this should only happen at the
                //start of a row
                else if ( i != 0 )
                {
                    fprintf(
                        stderr,
                        "Warning: Ran out of digits in the middle of "
                        "a row!\n"
                    );
                }

                //we cannot use "break" here, because that would
                //only break out of the innermost loop, but we must
                //break out of two levels of nested looops
                goto break_out_of_nested_loop;
            }

            //verify that we are not going to write to the array
            //out of bounds
            if ( num_rows == MAX_ROWS )
            {
                fprintf(
                    stderr,
                    "Too many rows to fit in the array! Stopping..."
                );

                goto break_out_of_nested_loop;
            }

            //add found character to the array
            myArr[num_rows][i] = p[0];

            //go to next character
            p++;

            //print warning message and stop if next character exists
            //and is not a whitespace character (i.e. space,
            //newline, etc.)
            if ( !isspace( (unsigned char)*p ) )
            {
                if ( *p != '\0' )
                {
                    fprintf(
                        stderr, 
                        "Warning: Unspected character found! "
                        "Stopping...\n"
                    );
                    goto break_out_of_nested_loop;
                }
            }
            else
            {
                //NOTE: This block will be skipped if we
                //are already at the end of the string, due to
                //the nested "if" statements above

                //go to next character
                p++;
            }
        }

        //increase the number of valid rows in the array
        num_rows++;
    }

break_out_of_nested_loop:

    //print the content of the array
    for ( int i = 0; i < num_rows; i++ )
    {
        for ( int j = 0; j < COLS_PER_ROW; j++ )
        {
             printf( "%c ", myArr[i][j] );
        }

        printf( "\n" );
    }
}

此程序与第一个程序具有相同的输出。

相关问题