Realloc arguments vector and string manipulation - c

I am asked to implement a reduced system shell that needs to be coded in C, and I have to achieve some of the features of an UNIX shell.
One of them is the replacement of ~[USER] to USER home dir, if USER appears, or the default environment variable "HOME" if it doesn't. I could write the code that iterates all over the commands (i.e. "ls ~hxshfx | sort | echo $var" -> argvv = {ls ~hxshfx, sort, echo $var}, but I can't figure out what to code if I want to change the own argvv value (i.e, ls /home/hxshfx | sort | echo a). I know I should use realloc but I don't understand how to use it when no malloc has been called. I do have another if statement for variables like $VAR but the problem is the same, the reallocation of information at argvv[i][j] position.
This is my code snippet:
void metacharacters (char *** argvv) {
int i, j;
char user, var, * aux, * toSubstitute, * name;
user = '~';
var = '$';
for (i = 0; argvv[i] != NULL; i++) {
for (j = 0; (aux = argvv[i][j]) != NULL; j++) {
if (aux[0] == user) {
struct passwd * pswd;
if (strlen(aux) > 1) {
name = (char *) struct passwd * pswd;malloc(sizeof(char) * (strlen(aux)-1));
strncpy(name, aux + 1, strlen(aux)-1);
pswd = getpwnam(name);
toSubstitute = pswd -> pw_dir;
free(name);
} else {
toSubstitute = getenv("HOME");
}
// TODO changes to argvv[i][j]
} else if (aux[0] == var) {
name = (char *) malloc(sizeof(char) * (strlen(aux)-1));
strncpy(name, aux + 1, strlen(aux)-1);
toSubstitute = getenv(name);
// TODO changes to argvv[i][j]
free(name);
}
}
}
}
The other thing I don't know how to solve is the shell function "set". When the shell recieves, i.e., "set myvar 1" it should use putenv to set the environment variable "myvar". I do think my function used to set the variable works okay:
void setVariable (char * arg1, char * arg2) {
int ret;
char * command = strdup(arg1);
strcat(command, "=");
strcat(command, arg2);
// i.e., at this point, command = "myvar=1", since arg1 = myvar; arg2 = 1
ret = putenv(command);
if (ret < 0) {
perror("putenv");
exit(1);
}
printf("%s=%s\n", arg1, getenv(arg1));
// I do think it works because getenv(arg1) works fine
free(command);
}
But, in the next iteration (or just outside the function setVariable), if I check what is the value of the environment variable "myvar", I always got null, no matter what. Also, if I print all the environment variables, there is no entry with "myvar" name, which is strange since, in the setVariable function, I had getenv(name) and that goes OK.
Thank you.

Related

Cannot seem to figure out why my program suddenly stops running after allocating some memory to a string

I'm working on some c code that dynamically allocates memory to an array of strings with a struct.
It basically can be initilized by DSA_INIT(name_of_variable) and strings can be appended with name_of_variable = arrcpy_str(name_of_variable, "some text"); and will append to the string, here is a small example:
DSA_INIT(test)
test = arrcpy_str(test, "hello world!");
// test.size is the amount of strings in the array, if test.size > 0 then it has values stored in it.
printf("Last value: %s\nLength: %d\n", test.contents[test.size - 1], test.size);
test = arrcpy_str(test, "test!");
printf("Last value: %s\nLength: %d\n", test.contents[test.size - 1], test.size);
Output:
Last value: hello world!
Length: 1
Last value: test!
Length: 2
As expected, but sometimes, quite bizarrely it breaks...
I was writing another function for the windows operating system, it's quite complicated so instead of posting like 200 lines of code I'll just summarize what it does (in the parts where there are no issues):
os_listdir takes 2 parameters, the directory, and the index. it returns a char * to the index in alphabetical order starting at one of the directory.
e.g. C:\Users\usrname\Desktop contains 2 files: named a.txt and b.txt.
os_listdir("C:\Users\usrname\Desktop", 1) = ".",
os_listdir("C:\Users\usrname\Desktop", 2) = "..",
os_listdir("C:\Users\usrname\Desktop", 3) = "a.txt" and finally,
os_listdir("C:\Users\usrname\Desktop", 4) = "b.txt"
os_listdir returns "N/A" if the directory cannot be found or there are not enough files to get the index.
length is the same as strlen from string.h and strequals is the same as strcmp from string.h
os_isdir returns true if it is a directory and concat concatenates 2 strings. rstrip and replace work like pythons rstrip and replace (pretty self-explanatory for the rest ig)
My code doesnt seem to work however in this, for no seemingly reason.
array source:
struct DYNAMIC_STRING_ARRAY {
char ** contents;
int size;
};
#define DSA struct DYNAMIC_STRING_ARRAY
#define DSA_INIT(DSA_to_initilize) DSA DSA_to_initilize; DSA_to_initilize.size = 0;
/* Returns length of a string excluding null terminator */
int length(const char * __s) {
int i;
for (i = 0; __s[i] != '\0'; ++i);
return i;
}
DSA arrcpy_str(DSA __a, char * to_add) {
DSA __arr = __a;
// It stops right below this line - it works normally but for some reason it stops in this function only:
// Even if i try to do something like directory_list = arrcpy_str(directory_list, "test"); it still wont work.
__arr.contents[__arr.size] = (char *) malloc(length(to_add) * sizeof(char));
__arr.contents[__arr.size] = to_add;
__arr.size++;
return __arr;
}
DSA arrcpy(DSA __a, DSA __add) {
DSA __arr = __a;
for (int i = 0; i < __add.size; i++) {
__arr.contents[__arr.size] = (char *) malloc(length(__add.contents[i]) * sizeof(char));
__arr.contents[__arr.size + i] = __add.contents[i];
__arr.size++;
}
return __arr;
}
and finally the os_listalldir source that is giving me trouble:
DSA os_listalldir(char * _path) {
char * path = rstrip(replace(_path, '/', '\\'), '\\');
DSA_INIT(directory_list)
directory_list = arrcpy_str(directory_list, "test");
if (!os_isdir(path)) {
free(path);
return directory_list;
}
int i = 1;
char * c_directory = os_listdir(path, i);
while (!strequals(c_directory, "N/A")) {
i++;
if (!strequals(c_directory, "..") && !strequals(c_directory, ".")) {
char * full_path = concat(path, concat("\\", c_directory));
// This line below is what breaks the code - refer to the source above to see where it actually stops
directory_list = arrcpy_str(directory_list, full_path);
if (os_isdir(full_path)) {
directory_list = arrcpy(directory_list, os_listalldir(full_path));
}
printf("%s\n", full_path);
}
c_directory = os_listdir(path, i);
}
free(path);
return directory_list;
}
The main problem being it stops running completely after the malloc part in arrcpy_str for some reason, I was wondering if someone could help me figure out why (it sometimes works but it sometimes doesn't??) however in the os_listalldir function it always stops running at that one commented line.

Invalid read of size 1 Valgrind error

In my program, the function read_commands just gets 2 strings and puts it into the struct Commands and returns the filled struct.
Apparently I have some fault in my logic. I'm getting the error:
Invalid read size of 1
In valgrind.
typedef struct{
Command *test
Command *compile
}Commands;
typedef struct Command{
char *command;
struct Command *next;
}Command;
I just do read_commands("abc", "abc");
The rest of my code:
Commands read_commands(const char *compile_cmds, const char *test_cmds) {
Commands commands;
Command *compile, *test;
int i;
if (compile_cmds == NULL || test_cmds == NULL)
exit(0);
compile = commands.compile;
test = commands.test;
i = 0;
while (compile_cmds + i != NULL) {
compile = malloc(sizeof(Command));
compile->command = malloc(strlen((compile_cmds + i) + 1));
strcpy(compile->command, compile_cmds + i);
compile = compile->next;
i++;
}
i = 0;
while (test_cmds + i != NULL) {
test = malloc(sizeof(Command));
test->command = malloc(strlen((test_cmds + i) + 1));
strcpy(test->command, test_cmds + i);
test = test->next;
i++;
}
return commands;
}
You should change the arguments to accept multiple commands e.g.
Commands read_commands(const char** compile_cmds, const char** test_cmds)
then you call it with:
char* compileCmds[] = { "abc", NULL };
char* testCmds[] = { "abc", NULL };
Commands c = read_commands(compileCmds,testCmds);
Meanwhile in your function to get all "compile" commands:
Commands commands = { NULL, NULL };
...
Command* last = NULL;
for (i = 0; compile_cmds[i] != NULL; ++i)
{
compile = malloc(sizeof(Command));
// check if we have added before, or if it is the first compile command
if (last!=NULL)
{
// last command, so append
last->next = compile;
}
else
{
// first command, set as first
commands->compile = compile;
}
// add the payload
compile->command = strdup(compile_cmds[i]);
compile->next = NULL;
// keep track of last to easy append
last = compile;
}
...
you may have noticed you have duplicate code in your function, so an idea would be to create a function read_commands for one of the compile or tests at a time and call it twice instead.
e.g.
read_commands(Command** cmd, const char** cmds);
...
Commands c = {NULL,NULL};
read_commands(&c.compile, compileCmds);
read_commands(&c.test, testCmds);
the extra * is for to be able to change what the pointer points to
read_commands(Command** pc, const char* cmds)
{
...
*pc = malloc(sizeof(Command));
...
}

How to create an array consisting of the tokens created using the strtok function?

I am new with .ini files and thus this qn(which might seem silly) .I have created a .ini file and access it via my C program. The ini file looks like this:
[key]
title = A,H,D
The C program accesses it using:
LPCSTR ini ="C:\\conf.ini;
char var[100];
GetPrivateProfileString("key", "title", 0, var, 100, ini);
printf("%s", var);
char* buffer = strtok(var, ", ");
do{
printf("%s", buffer);
if (strcmp(buffer, "A")==0)
printf("Hello");
puts("");
}while ((buffer=strtok(NULL, ", "))!= NULL);
output looks as :
A H D F G IAHello
H
D
F
G
Now what I need to do is use these individual tokens again to form an array with indices within my C program. For example:
char x[A, H, D, F, G]
so that when I refer to the index 2, x[2] should give me 'D'. Could somebody suggest a way to do this. I have never used strtok before and thus very confused. Thank you in advance.
This question is quite similar to others regarding getting external information and storing it in an array.
The problem here is the amount of elements in your array to store.
You could use Link-lists, but for this example, I would scan the file, getting the total amount of items needed for the array - and then parse the file data again - storing the items in the array.
The first loop, goes through and counts the items to be store, as per your example posted. I will do the second loop just as an example - please note in my example you would of created nTotalItems and have counted the amount of items, storing that in nTotalItems ... I am assuming you want to store a string, not just a char...
Also please note this a draft example, done at work - only to show a method of storing the tokens into an array, therefore there is no error checking ec
// nTotalItems has already been calculated via the first loop...
char** strArray = malloc( nTotalItems * sizeof( char* ));
int nIndex = 0;
// re-setup buffer
buffer = strtok(var, ", ");
do {
// allocate the buffer for string and copy...
strArray[ nIndex ] = malloc( strlen( buffer ) + 1 );
strcpy( strArray[ nIndex ], buffer );
printf( "Array %d = '%s'\n", nIndex, strArray[ nIndex ] );
nIndex++;
} while ((buffer=strtok(NULL, ", "))!= NULL);
Just use an INI parser that supports arrays.
INI file:
[my_section]
title = A,H,D
C program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <confini.h>
#define MY_ARRAY_DELIMITER ','
struct configuration {
char ** title;
size_t title_length;
};
static char ** make_strarray (size_t * arrlen, const char * src, const size_t buffsize, IniFormat ini_format) {
*arrlen = ini_array_get_length(src, MY_ARRAY_DELIMITER, ini_format);
char ** const dest = *arrlen ? (char **) malloc(*arrlen * sizeof(char *) + buffsize) : NULL;
if (!dest) { return NULL; }
memcpy(dest + *arrlen, src, buffsize);
char * iter = (char *) (dest + *arrlen);
for (size_t idx = 0; idx < *arrlen; idx++) {
dest[idx] = ini_array_release(&iter, MY_ARRAY_DELIMITER, ini_format);
ini_string_parse(dest[idx], ini_format);
}
return dest;
}
static int ini_handler (IniDispatch * this, void * v_conf) {
struct configuration * conf = (struct configuration *) v_conf;
if (this->type == INI_KEY && ini_string_match_si("my_section", this->append_to, this->format)) {
if (ini_string_match_si("title", this->data, this->format)) {
/* Save memory (not strictly needed) */
this->v_len = ini_array_collapse(this->value, MY_ARRAY_DELIMITER, this->format);
/* Allocate a new array of strings */
if (conf->title) { free(conf->title); }
conf->title = make_strarray(&conf->title_length, this->value, this->v_len + 1, this->format);
if (!conf->title) { return 1; }
}
}
return 0;
}
static int conf_init (IniStatistics * statistics, void * v_conf) {
*((struct configuration *) v_conf) = (struct configuration) { NULL, 0 };
return 0;
}
int main () {
struct configuration my_conf;
/* Parse the INI file */
if (load_ini_path("C:\\conf.ini", INI_DEFAULT_FORMAT, conf_init, ini_handler, &my_conf)) {
fprintf(stderr, "Sorry, something went wrong :-(\n");
return 1;
}
/* Print the parsed data */
for (size_t idx = 0; idx < my_conf.title_length; idx++) {
printf("my_conf.title[%d] = %s\n", idx, my_conf.title[idx]);
}
/* Free the parsed data */
if (my_conf.title_length) {
free(my_conf.title);
}
return 0;
}
Output:
my_conf.title[0] = A
my_conf.title[1] = H
my_conf.title[2] = D

Thread 1: EXC_BAD_ACCESS (code=1, address=0x0) standard C memory issue

I'm writing code to compare two input files in standard C, using the Xcode IDE. I keep getting this error: Thread 1: EXC_BAD_ACCESS (code=1, address=0x0). I've done some reading on this and believe it to be a memory issue, but no matter what I try I can't seem to fix it (I've also tried making the structures dynamically using malloc and listed that at the bottom of the code). It's strange because it writes all of the data and then spits out that error at the end. The file format is something like this:
start(int)..stop(int) id(+ or -) now some stuff I don't care about for the rest of the line
I've just been testing this on a file with only + id's so the "-" aspect isn't part of the issue. Anyway I'm quite tired and have been staring at this for a few hours, so please forgive me if it doesn't make sense, I will update it after a few hours of sleep.
typedef struct
{
int start;
int stop;
char *strandID;
} location;
int main(int argc, const char * argv[])
{
if (argc != 4)
{
fprintf(stderr,
"Usage is ./a.out windowfile.txt genefile.txt outputFileName");
exit(-1);
}
//const vars
const char *windowInput = argv[1];
const char *geneInput = argv[2];
const char *outputfile = argv[3];
const int windowHeader = 9;
const int geneHeader = 3;
//get size of structures -- I have debugged and these work correctly, returning the size of my structure
const int posWsize = getSize(windowInput, "+", windowHeader);
const int negWsize = getSize(windowInput, "-", windowHeader);
const int posGsize = getSize(geneInput, "+", geneHeader);
const int negGsize = getSize(geneInput, "-", geneHeader);
//declare structs
location posWindow[posWsize];
location negWindow[negWsize];
location posGene[posGsize];
location negGene[negGsize];
//extract data here
getLocations(posWindow, negWindow, windowInput, windowHeader);
return 0;
}
void getLocations(location *posL, location *negL, const char *input,
const int header)
{
FILE *fileptr = NULL;
fileptr = fopen(input, "r"); //open file
if (fileptr == NULL)
{ //check for errors while opening
fprintf(stderr, "Error reading %s\n", input);
exit(-1);
}
char tmpLoc[20];
char tmpID[2];
int eofVar = 0;
int lineCount = 0;
while (lineCount < header)
{ //skip header and get to data
eofVar = fgetc(fileptr);
if (eofVar == '\n')
lineCount++;
}
int pCount = 0;
int nCount = 0;
while (eofVar != EOF)
{
fscanf(fileptr, "%s %s", tmpLoc, tmpID); //scan in first two strings
if (!strcmp(tmpID, "+"))
{ //if + strand
char *locTok = NULL;
locTok = strtok(tmpLoc, ".."); //tok and get values
posL[pCount].start = atoi(locTok);
locTok = strtok(NULL, "..");
posL[pCount].stop = atoi(locTok); //ERROR IS SHOWN HERE
posL[pCount].strandID = tmpID;
printf("start=%d\tstop=%d\tID=%s\tindex=%d\n", posL[pCount].start,
posL[pCount].stop, posL[pCount].strandID, pCount);
pCount++;
}
else if (!strcmp(tmpID, "-"))
{ //if - strand
char *locTok = NULL;
locTok = strtok(tmpLoc, ".."); //tok and get values
negL[nCount].start = atoi(locTok);
locTok = strtok(NULL, "..");
negL[nCount].stop = atoi(locTok);
negL[nCount].strandID = tmpID;
nCount++;
}
while ((eofVar = fgetc(fileptr)) != '\n')
{
if (eofVar == EOF)
break;
}
}
fclose(fileptr);
}
//dynamic way...same issue -- just replace this with the above if statement and use the create location function
if (!strcmp(tmpID, "+"))
{ //if + strand
int locStart;
int locStop;
locStart = atoi(strtok(tmpLoc, ".."));//tok and get values
locStop = atoi(strtok(NULL, ".."));
posL[pCount] = *createlocation(locStart, locStop, tmpID);
pCount++;
}
location *createlocation(int start, int stop, char *strandID)
{
location *tmp = NULL;
tmp = (location *) malloc(sizeof(location) * 1);
tmp->start = start;
tmp->stop = stop;
tmp->strandID = (char *) malloc(sizeof(char) * 2);
strcpy(tmp->strandID, strandID);
return tmp;
}
Check the return value of strtok.
In your code here
locTok = strtok(NULL, "..");
posL[pCount].stop = atoi(locTok); //ERROR IS SHOWN HERE
strtok is returning a NULL pointer and according to documentation,
A null pointer is returned if there are no tokens left to retrieve.
which matches my original guess that because the address code is 0x0 there's a NULL pointer deference somewhere.
Obviously, the following call to atoi is expecting a non-NULL pointer and crashes.
You Can Also Use Exception Breakpoint in Xcode.
An exception breakpoint tells the debugger to pause whenever a problem is encountered anywhere in your program, so you can evaluate your program's state before it crashes.
Go to the Breakpoint Navigation (Cmd+8), then click the + button in the bottom left and choose Add Exception Breakpoint. You can leave it there.
In my case, I was using the wrong block type. For some reason, a developer had marked a block as const id blockName = ^(Type variableName) { /* code */ } but unfortunately the Type mismatched . Because blockNamewas declared as typeid, the compiler could not warn me properly when I passed blockName` as an argument somewhere else, and this error happened at runtime instead.
For example:
const id callback = ^(ARTPaginatedResult<ARTMessage *> * _Nullable paginatedResult, ARTErrorInfo * _Nullable error) { /* code */
[channel setOptions:channelOptions callback:callback];
The block above has 3 parameters, but channel:setOptions:callback: defines 1 argument called callback, which must be a block which takes 1 argument, and is declared as
- (void)setOptions:(ARTRealtimeChannelOptions *_Nullable)options callback:(nullable void (^)(ARTErrorInfo *_Nullable))cb;
for xc
in your main() function, try to remove char*argv[] or both arguments.
You should delete the arguments of you main function. And it will work.

How to overwrite an array of char pointers with a larger list of char pointers?

My function is being passed a struct containing, among other things, a NULL terminated array of pointers to words making up a command with arguments.
I'm performing a glob match on the list of arguments, to expand them into a full list of files, then I want to replace the passed argument array with the new expanded one.
The globbing is working fine, that is, g.gl_pathv is populated with the list of expected files. However, I am having trouble copying this array into the struct I was given.
#include <glob.h>
struct command {
char **argv;
// other fields...
}
void myFunction( struct command * cmd )
{
char **p = cmd->argv;
char* program = *p++; // save the program name (e.g 'ls', and increment to the first argument
glob_t g;
memset(&g, 0, sizeof(g));
g.gl_offs = 1;
int res = glob(*p++, GLOB_DOOFFS, NULL, &g);
glob_handle_res(res);
while (*p)
{
res = glob(*p, GLOB_DOOFFS | GLOB_APPEND, NULL, &g);
glob_handle_res(res);
}
if( g.gl_pathc <= 0 )
{
globfree(&g);
}
cmd->argv = malloc((g.gl_pathc + g.gl_offs) * sizeof *cmd->argv);
if (cmd->argv == NULL) { sys_fatal_error("pattern_expand: malloc failed\n");}
// copy over the arguments
size_t i = g.gl_offs;
for (; i < g.gl_pathc + g.gl_offs; ++i)
cmd->argv[i] = strdup(g.gl_pathv[i]);
// insert the original program name
cmd->argv[0] = strdup(program);
** cmd->argv[g.gl_pathc + g.gl_offs] = 0; **
globfree(&g);
}
void
command_free(struct esh_command * cmd)
{
char ** p = cmd->argv;
while (*p) {
free(*p++); // Segfaults here, was it already freed?
}
free(cmd->argv);
free(cmd);
}
Edit 1: Also, I realized I need to stick program back in there as cmd->argv[0]
Edit 2: Added call to calloc
Edit 3: Edit mem management with tips from Alok
Edit 4: More tips from alok
Edit 5: Almost working.. the app segfaults when freeing the command struct
Finally: Seems like I was missing the terminating NULL, so adding the line:
cmd->argv[g.gl_pathc + g.gl_offs] = 0;
seemed to make it work.
argv is an array of pointers of char *. This means that argv has space for argc char * values. If you try to copy more than that many char * values into it, you will end up with an overflow.
Most likely your glob call results in more than argc elements in gl_pathv field (i.e, gl_pathc > argc). This is undefined behavior.
It is similar to the code below:
/* Wrong code */
#include <string.h>
int a[] = { 1, 2, 3 };
int b[] = { 1, 2, 3, 4 };
memcpy(a, b, sizeof b);
Solution: you should either work with the glob_t struct directly, or allocate new space to copy gl_pathv to a new char **:
char **paths = malloc(g.gl_pathc * sizeof *paths);
if (paths == NULL) { /* handle error */ }
for (size_t i=0; i < g.gl_pathc; ++i) {
/* The following just copies the pointer */
paths[i] = g.gl_pathv[i];
/* If you actually want to copy the string, then
you need to malloc again here.
Something like:
paths[i] = malloc(strlen(g.gl_pathv[i] + 1));
followed by strcpy.
*/
}
/* free all the allocated data when done */
Edit: after your edit:
cmd->argv = calloc(g.gl_pathc, sizeof(char *) *g.gl_pathc);
it should work, but each of argv[1] to argv[g.gl_pathc + g.gl_offs - 1] is a char * that is "owned" by the struct glob. Your memcpy call is only copying the pointers. When you later do globfree(), those pointers don't mean anything anymore. So, you need to do copy the strings for your use:
size_t i;
cmd->argv = malloc((g.gl_pathc+g.gl_offs) * sizeof *cmd->argv);
for (i=g.gl_offs; i < g.gl_pathc + g.gl_offs; ++i)
cmd->argv[i] = strdup(g.gl_pathv[i]);
This makes sure you now have your own private copies of the strings. Be sure to free them (and argv) once you are done.
There are a few other problems with your code.
You are doing *p++, you should do p++, since you're not using the value of the dereferencing.
You should really check the return value of glob.
Your paths variable needs g.gl_pathc + 1 elements, not g.gl_pathc. (Or more correctly, you need to allocate g.gl_pathc + g.gl_offs times sizeof *paths bytes.)
Your for loop to copy strings should be for (j=1; j < g.gl_pathc + g.gl_offs; ++j).
Make sure you prevent shell from expanding your glob. I.e., call ./a.out '*' instead of ./a.out *.
Don't you need to multiple g.gl_pathc by sizeof(char *)?

Resources