strtok和存储在数组中:输出不是预期的

时间:2016-11-03 05:55:25

标签: c multidimensional-array strtok

在下面的代码中,文件test.txt包含以下数据:
    192.168.1.1-90
    192.168.2.2-80

此输出不符合预期。 我希望输出为
192.168.1.1
90个
192.168.2.2
80个
任何帮助将不胜感激。

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
  FILE *fp;
  char *result[10][4];
  int i=0;
  const char s[2] = "-";
  char *value,str[128];
  fp = fopen("test.txt", "r");
  if (fp == NULL)
    printf("File doesn't exist\n");
  else{
    while(!feof(fp)){

      if(fgets(str,sizeof(str),fp)){

        /* get the first value */
        value = strtok(str, s);
        result[i][0]=value;
        printf("IP : %s\n",result[i][0]); //to be removed after testing


        /* get second value */
        value = strtok(NULL, s);
        result[i][1]=value;
        printf("PORT : %s\n",result[i][1]); //to be removed after testing
        i++;
     }}
    for (int k=0;k<2;k++){
        for (int j=0;j<2;j++){
            printf("\n%s\n",result[k][j]);
       }
   }

 }
        return(0);
 }

2 个答案:

答案 0 :(得分:0)

您可以尝试此解决方案。它使用动态内存代替,但是做了你的事。

代码:

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

#define BUFFSIZE 128

void exit_if_null(void *ptr, const char *msg);

int
main(int argc, char const *argv[]) {
    FILE *filename;
    char buffer[BUFFSIZE];
    char *sequence;
    char **ipinfo;
    int str_size = 10, str_count = 0, i;

    filename = fopen("ips.txt", "r");

    if (filename == NULL) {
        fprintf(stderr, "%s\n", "Error Reading File!");
        exit(EXIT_FAILURE);
    }

    ipinfo = malloc(str_size * sizeof(*ipinfo));
    exit_if_null(ipinfo, "Initial Allocation");

    while (fgets(buffer, BUFFSIZE, filename) != NULL) {
        sequence = strtok(buffer, "-\n");

        while (sequence != NULL) {
            if (str_size == str_count) {
                str_size *= 2;
                ipinfo = realloc(ipinfo, str_size * sizeof(*ipinfo));
                exit_if_null(ipinfo, "Reallocation");
            }

            ipinfo[str_count] = malloc(strlen(sequence)+1);
            exit_if_null(ipinfo[str_count], "Initial Allocation");

            strcpy(ipinfo[str_count], sequence);

            str_count++;

            sequence = strtok(NULL, "-\n");
        }
    }

    for (i = 0; i < str_count; i++) {
        printf("%s\n", ipinfo[i]);
        free(ipinfo[i]);
        ipinfo[i] = NULL;
    }

    free(ipinfo);
    ipinfo = NULL;

    fclose(filename);

    return 0;
}

void
exit_if_null(void *ptr, const char *msg) {
    if (!ptr) {
        printf("Unexpected null pointer: %s\n", msg);
        exit(EXIT_FAILURE);
    }
}

答案 1 :(得分:0)

要理解的关键是char *strtok(char *str, const char *delim)在内部修改str指向的字符串并使用它来存储结果。所以返回的指针实际指向str中的某个地方。

在您的代码中,每次解析文件中的新行时都会刷新str的内容,但地址保持不变。因此,在while循环之后,str的内容是文件的最后一行,以某种方式由strtok修改。目前,result[0][0]result[1][0]都指向同一地址,该地址等于str的开头。所以你最后两次打印相同的东西。

在添加到您的代码中的注释中进一步说明了这一点。

int main()
{
    FILE *fp;
    char *result[10][4];
    int i=0;
    const char s[2] = "-";
    char *value,str[128];
    fp = fopen("test.txt", "r");
    if (fp == NULL)
        printf("File doesn't exist\n");
    else{
        while(!feof(fp)){

            if(fgets(str,sizeof(str),fp)){

                /* get the first value */
                value = strtok(str, s);
                // ADDED: value now points to somewhere in str
                result[i][0]=value;
                // ADDED: result[i][0] points to the same address for i = 0 and 1
                printf("IP : %s\n",result[i][0]); //to be removed after testing


                /* get second value */
                value = strtok(NULL, s);
                // ADDED: value now points to somewhere in str
                result[i][1]=value;
                // ADDED: result[i][1] points to the same address for i = 0 and 1
                printf("PORT : %s\n",result[i][1]); //to be removed after testing
                i++;
            }}
        // ADDED: now result[0][0]==result[1][0], result[0][1]==result[1][1], you can test that
        for (int k=0;k<2;k++){
            for (int j=0;j<2;j++){
                printf("\n%s\n",result[k][j]);
            }
        }

    }
    return(0);
}

要获得预期的输出,您应该每次将strtok返回的指针指向的字符串复制到其他位置,而不是仅复制指针本身。