0

I swear I really am a decent programmer but my adventures in C programming after programming in Java for years are driving me mad.

I'm trying to fill a two dimensional char array with a set of IP Address/Port pairs. I'm reading them in from a file. They are being pulled out of the file correctly, and, should be being placed into the array correctly. The problem is that for some reason when the second set is being placed into the array it's overwriting the first set and I cannot for the life of me figure out why.

The first line of the file is the number of IP Address/Port pairs in the file (I call them tuples). The following lines are the IP addresses and ports separated by a space.

Here is the code:

 //read the top line with the number of items
  fgets(line, sizeof line, fp);
  numLines = atoi(line);
  printf("%s %d\n","numLines:",numLines);
  char* tuples[numLines][2];
  char* rawLines[numLines];
  //read each line and put it into array
  for(currentLine=0; currentLine<numLines; currentLine++){
    if(fgets(line, sizeof line, fp) == NULL){
      perror("fgets");
      return -1;
    }
    printf("%s %d \n","curentLine: ",currentLine);
    char* port;
    tuples[currentLine][0] = strtok(line, " ");
    printf("%s %s \n", "IP Address: ", tuples[currentLine][0]);
    //rawLines[currentLine] = line;
    port = strtok(NULL, " ");
    size_t ln = strlen(port) - 1;
    if (port[ln] == '\n')
      port[ln] = '\0';
    tuples[currentLine][1]=port;
    printf("%s %s\n","port: ", tuples[currentLine][1]);
  }
  //list created and stored in tuples
  //now that list is created choose a random server from the file and strip the value chosen from the list

  //choose random server
  srand (time(NULL));
  //randomServer = rand()%numLines;
  randomServer = 0;
  printf("%s %d\n", "randomServer: ", randomServer);



  //connect to random server pulled
  memset(&hints, 0, sizeof hints); // make sure the struct is empty
  hints.ai_family = AF_UNSPEC;     // don't care IPv4 or IPv6
  hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
  hints.ai_flags = AI_PASSIVE;     // fill in my IP for me
  //setup client socket
  printf("%s %s \n", "Setting up connection to: ", tuples[randomeServer][0]);
  printf("%s %s \n", "Setting up connection on port: ", tuples[randomServer][1]);

Here is the output I get:

numLines: 2
curentLine:  0
IP Address:  127.0.0.1
port:  3761
curentLine:  1
IP Address:  192.168.0.1
port:  3762
randomServer:  0
Setting up connection to:  192.168.0.1
Setting up connection on port:  1

What I expect to get is: Setting up connection to: 127.0.0.1 Setting up connection on port: 3761

If I only have one line in the file then I get the expected values.

Thank you in advance.

natediggs
  • 61
  • 1
  • 8
  • 1
    Seems like a typical symptom of assigning a pointer to an array of which the content changes later. Apart from that: 1. **thank you** for using `fgets()` instead of the brain-dead `scanf()` (which for some reason everyone likes to (ab)use), 2. but why `printf("%s %d\n","numLines:",numLines);`? A more readable version would be `printf("numLines: %d\n", numLines);`. Furthermore, `strtol()` is preferred over `atoi()`. –  Oct 09 '13 at 19:40
  • Shouldn't it be `sizeof(line)`? – John Oct 09 '13 at 19:42
  • @John No, why? `line` is an object, not a type. –  Oct 09 '13 at 19:42
  • 1
    Maybe `strcpy` can solve your problem? – Mauren Oct 09 '13 at 19:43
  • @H2CO3 How can you tell that it's not a char array? – John Oct 09 '13 at 19:49
  • @John Non sequitur. It presumably **is** an array of `char`s. What exactly is you problem? –  Oct 09 '13 at 19:50
  • @H2CO3 Nothing now. I figured out why I was confused. – John Oct 09 '13 at 19:56

4 Answers4

2

Instead of directly assigning strtok return to your bidimensional array, copy the contents with strcpy:

char *ipAddress = strtok(line, " ");
char *tuple0 = malloc(sizeof(char) * (strlen(ipAddress) + 1));
strcpy(tuple0, ipAddress);
tuples[currentLine][0] = tuple0;
Mauren
  • 1,955
  • 2
  • 18
  • 28
  • 1
    A couple notes about this: The malloc call needs a +1 for the null terminator. If you `strcpy` "abc" then 4 bytes are needed. Secondly, the `strcat` is not needed. strcpy already null terminates the result (and if it didn't then `strcat` would not work because it requires a null terminated target to start with :). – Mark Wilkins Oct 09 '13 at 20:38
0

The problem is that you're not copying the data correctly. You have a variable named line, which appears to be an array of char, and you use fgets() to read each line of the input into this variable. You then tokenize the input, and for each token, you're storing a pointer into the line array to a location in the tuples array, but this data gets overwritten as soon as you read in the next line. What you really need to be doing is allocating a new piece of storage, copying the data into that, and storing the pointer to that new storage into the tuples array.

This isn't my real name
  • 4,869
  • 3
  • 17
  • 30
0

Seems like you did not allocate memory for your "saved" strings. Your declarations:

char* tuples[numLines][2];
char* rawLines[numLines];

declares arrays of pointers to char. Not "strings". So you are missing something like:

tuples[index_value][0] = malloc(number_of_characters); 

And then you should write the lines you read in that memory with either strcpy or strncpy.

sizeof(char) is always one

Community
  • 1
  • 1
Sebastien
  • 1,439
  • 14
  • 27
0

It is worth remembering that there are no 2D arrays in C. A 2D array is an abstract concept which can be implemented in C with (at least) two different concrete constructs. There are arrays of arrays, and there are arrays of pointers.

When we are talking about arrays of pointers, we usually (not always) arrange them such that the individual pointers point to different chunks of memory, lest our abstract 2D array ends up containing duplicates of the same row. In order for this to happen, we normally allocate each row explicitly on the heap, then fill it with values. Note that strtok doesn't allocate anything. It accepts a character array and returns pointers that point inside it (and destroys the original string that was there).

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243