简体   繁体   中英

Breaking a c string into tokens through strtok

In the following piece of code, i see that after breaking userHostPairs in tokens and assigning to itself doesn't work. After breaking into tokens i print userHostPairs in loop and in the same loop i also print 0th element always through printf("0Printing after strtok = %s",userHostPairs[0]); which prints weird values(most probably the last fetched value).

FILE* fp;        
char  line[100];        
char* userHostPairs[100];

fp = fopen("somefile", "r");

//READING THE FILE LINE BY LINE. WORKS FINE  
        int count =0;
        while (fgets(line, sizeof(line), fp) != NULL ) {
                userHostPairs[count]=malloc(MAX_LINE_SIZE);
                strcpy(userHostPairs[count],line);
                count++;
        }

///PROBLEMATIC CODE////////////////////

        for(i=0;i<count;i++)
        {
                char temp[100];
                strcpy(temp,userHostPairs[i]);

                userHostPairs[i] = strtok(temp,"@");
                userHostPairs[i] = strtok(NULL,"@");
                printf("Printing after strtok = %s",userHostPairs[i]);
                printf("0Printing after strtok = %s",userHostPairs[0]); //This 0th element is always some random(or last) value fetched.
        }
}

Output:

Printing in strtok = 10.238.178.136
0Printing in strtok = 10.238.178.136
Printing in strtok = 10.238.152.101
0Printing in strtok = 10.238.152.101
Printing in strtok = eaasrt
0Printing in strtok = eaasrt
Printing in strtok = eaasrt7
0Printing in strtok = aasrt7

prints weird values(most probably the last fetched value).

this is because of several errors in your code

            char temp[100];

            userHostPairs[i] = strtok(temp,"@");
            userHostPairs[i] = strtok(NULL,"@");

the assignments are not what you want for 3 reasons :

  • you replace the mallocd block (rather than probably to strcpy in it), so you create a memory leak
  • you assign two times the same entry in userHostPairs , so the first result of strtok is lost
  • strtok returns pointers in temp and you modify temps the next loop so the previous results are broken

Of course when you will go out of the scope of temp any uses to pointer saved in userHostPairs will have an undefined behavior, but this is not the reason of the result you see because your writes are in the scope of temp


Example :

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

size_t read(size_t sz, char *a1[sz], char * a2[sz])
{
  FILE* fp = fopen("f", "r");

  if (fp == 0)
    return 0;

  char line[50];        
  size_t rank;

  for (rank = 0; rank != sz; ++rank) {
    if (fgets(line, sizeof(line), fp) == NULL)
      break;

    char * p1, * p2;

    if (((p1 = strtok(line, "@")) == NULL) ||
        ((p2 = strtok(NULL, "@\n")) == NULL))
      break;

    a1[rank] = malloc(strlen(p1) + 1);
    strcpy(a1[rank], p1);

    a2[rank] = malloc(strlen(p2) + 1);
    strcpy(a2[rank], p2);
  }

  fclose(fp);
  return rank;
}

#define N 50

int main()
{
  char * a1[N];
  char * a2[N];
  size_t n = read(N, a1, a2);

  for (size_t i = 0; i != n; ++i)
    printf("'%s' / '%s'\n", a1[i], a2[i]);

  /* ... */

  /* free resources */
  for (size_t i = 0; i != n; ++i) {
    free(a1[i]);
    free(a2[i]);
  }

  return 0;
}

Note if you have strdup you can replace

    a1[rank] = malloc(strlen(p1) + 1);
    strcpy(a1[rank], p1);

    a2[rank] = malloc(strlen(p2) + 1);
    strcpy(a2[rank], p2);

by

    a1[rank] = strsup(p1);
    a2[rank] = strdup(p2);

Having the file f containing :

aze@qsd@
wxc@iop
iop@jkl

Compilation and execution :

pi@raspberrypi:/tmp $ ./a.out
'aze' / 'qsd'
'wxc' / 'iop'
'iop' / 'jkl'
pi@raspberrypi:/tmp $ 

Execution under valgrind :

pi@raspberrypi:/tmp $ valgrind ./a.out
==6244== Memcheck, a memory error detector
==6244== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==6244== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==6244== Command: ./a.out
==6244== 
'aze' / 'qsd'
'wxc' / 'iop'
'iop' / 'jkl'
==6244== 
==6244== HEAP SUMMARY:
==6244==     in use at exit: 0 bytes in 0 blocks
==6244==   total heap usage: 9 allocs, 9 frees, 5,496 bytes allocated
==6244== 
==6244== All heap blocks were freed -- no leaks are possible
==6244== 
==6244== For counts of detected and suppressed errors, rerun with: -v
==6244== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
pi@raspberrypi:/tmp $ cat f

If you do not want to limit the number of elements in the arrays you can use malloc then realloc for the arrays :

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

size_t read(char *** a1, char *** a2)
{
  *a1 = malloc(0);
  *a2 = malloc(0);

  FILE* fp = fopen("f", "r");

  if (fp == 0)
    return 0;

  char line[50];        
  size_t rank = 0;

  while (fgets(line, sizeof(line), fp) != NULL) {
    char * p1, * p2;

    if (((p1 = strtok(line, "@")) == NULL) ||
        ((p2 = strtok(NULL, "@\n")) == NULL))
      break;

    *a1 = realloc(*a1, (rank+1) * sizeof(char *));
    (*a1)[rank] = malloc(strlen(p1) + 1);
    strcpy((*a1)[rank], p1);

    *a2 = realloc(*a2, (rank+1) * sizeof(char *));
    (*a2)[rank] = malloc(strlen(p2) + 1);
    strcpy((*a2)[rank], p2);

    rank += 1;
  }

  fclose(fp);
  return rank;
}

int main()
{
  char ** a1;
  char ** a2;
  size_t n = read(&a1, &a2);

  for (size_t i = 0; i != n; ++i)
    printf("'%s' / '%s'\n", a1[i], a2[i]);

  /* ... */

  /* free resources */
  for (size_t i = 0; i != n; ++i) {
    free(a1[i]);
    free(a2[i]);
  }
  free(a1);
  free(a2);

  return 0;
}

With the same file f , compilation and execution :

pi@raspberrypi:/tmp $ gcc -g -pedantic -Wextra -Wall st.c
pi@raspberrypi:/tmp $ ./a.out
'aze' / 'qsd'
'wxc' / 'iop'
'iop' / 'jkl'
pi@raspberrypi:/tmp $ 

Execution under valgrind :

pi@raspberrypi:/tmp $ valgrind ./a.out
==6423== Memcheck, a memory error detector
==6423== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==6423== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==6423== Command: ./a.out
==6423== 
'aze' / 'qsd'
'wxc' / 'iop'
'iop' / 'jkl'
==6423== 
==6423== HEAP SUMMARY:
==6423==     in use at exit: 0 bytes in 0 blocks
==6423==   total heap usage: 17 allocs, 17 frees, 5,544 bytes allocated
==6423== 
==6423== All heap blocks were freed -- no leaks are possible
==6423== 
==6423== For counts of detected and suppressed errors, rerun with: -v
==6423== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
pi@raspberrypi:/tmp $ 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM