2D array being overwritten in C

Hi i am trying to code a program that takes a file called cmdpipe in as input from stdin (./program < cmdpipe). I have managed to make the program read in every line, use strtok to parse it so i can use execvp later in the program (I have not reached that stage yet). I am trying to copy each line into a 2d array so that i can have access to the parsed lines at any stage because if i don’t use a 2d array the program will overwrite each line and i will only have the last line. After coding this i realised that when i try to access the 2d array inside the while loop where all the lines are being parsed, everything works fine. But if i try accessing the 2d array outside of the while loop the array returns doesn’t return the expected output.

Thanks so much in advance.

code in cmdpipe that is being fed into the program

ls -s1

sort -n

tail -n 5

code in program.c

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

#define MAX_ARGS 10
#define MAX_CHAR 256
#define MAX_LINE 100

/*  
    The parse_line function reads the input line by line and parses it to an array called args.
    The return value of the function is argCount which is the number of arguments in the line. 
*/

int parse_line(char* line, char** args){
    int argCount = 0;
    char* arg = strtok(line, " \n");
    while(arg != NULL && argCount < MAX_ARGS){
        args[argCount++] = arg;
        arg = strtok(NULL, " \n");
    }
    args[argCount] = NULL;
    return argCount;
}

int main(){
    char line[MAX_CHAR];
    char* args[MAX_ARGS+1];
    char* commands[MAX_LINE][MAX_ARGS+1];
    int status, argCount;
    int argCountArray[MAX_LINE];
    int row = 0;

/* 
    The following while function calls the parse line function to read every line in,
    the parsed line of commands is called args but this is only one line and everytime the while loop
    repeats the args array is over-written. so the while loop copies the values to a 2D array called
    "commands", it will ignore any empty line in cmdpipe file.
 */

    while(fgets(line, MAX_CHAR, stdin) != NULL){
        
        argCount = parse_line(line, args); // argCount is the number of arguments in a line of commands

        if (argCount > 0)
        {
            for (int col = 0; col < argCount; col++)
            {
                commands[row][col] = args[col];
                argCountArray[row] = argCount;
                printf("%s\n",commands[row][col]);
                printf("Row number: %d ||  || Col number: %d\n",row,col);
            }
            //printf("Number of arguments in this row is : %d\n",argCountArray[row]);
            row++; 
        }

    }  

    /* 
        write code that will pass the commands array to the execvp function and pipe the results
    */

    row = 0;
    while (row != MAX_LINE)
    {
        char* tempcmd[MAX_ARGS+1];    //copies a line of commands from commands array and puts it in this array so it can be execvp'd    

        for (int col = 0; col < argCountArray[row]; col++)
        {
            tempcmd[col] = commands[row][col];
            printf("%s\n",tempcmd[col]);
            printf("Row number: %d ||  || Col number: %d\n",row,col);
        }
        row++; 
    }

    return 0; 
}

when i try to access the 2d array inside the while loop where all the lines are being parsed, everything works fine. But if i try accessing the 2d array outside of the while loop the array returns doesn’t return the expected output.

>Solution :

The strtok() function modifies and returns pointers to the original string so your args[] and commands[][] arrays consist of pointers to different substrings in your line[] array. But on each iteration of your loop you read a new string into line[] which invalidates all of your previous pointers.

You’ll need to make a copy of each string and save pointers to those instead. The easiest way is probably using strdup():

args[argCount++] = strdup(arg);

You’ll need to free() these extra copies later in your program once you’re done with them.

Leave a Reply