Seg fault when printing array after passing to function, please explain behaviour - c

So i am attempting to pass a string array (char** arguments) to a function, fill the array with values and then print those values after returning from the function. The problem occurs when I try to print the first value of "arguments" which gives me a segmentation fault. Why is this? when I print the values in the "getArguments" function all goes as expected. I am new to C and yes this is an assignment. I am not looking for you to write this code for me however I would like an explanation of this behaviour as I try to understand this concept.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define BUFFERSIZE 81
int getArguments(char** arguments, char* argument);
void getPath(char* pathBuffer);
int checkForDirectoryChange(char **arguments, int num_args);
int main(int argc, char *argv[]){
char * command;
char ** arguments = NULL;
char * cd_path;
int len, pid, ret_code, cd_requested = 1;
char buffer[BUFFERSIZE];
/* Get user input and the first token */
printf("Enter a command: > ");
command = fgets(buffer,BUFFERSIZE,stdin);
printf("The command entered was %s",buffer);
len = strlen(buffer);
if(buffer[len-1] == '\n')
buffer[len-1]='\0';
cd_requested = getArguments(arguments, command);
printf("The argument passed is now: %s\n", arguments[0]);
if(cd_requested == 0){
fprintf(stdout,"Change directory requested.\n");
}
/*
char * pathBuf;
getPath(pathBuf);
free the memory allocated */
/*
pid = fork();
if(pid){
wait(NULL);
}else{
ret_code = execvp(*arguments, arguments);
if(ret_code){
printf("The fork failed, exiting.");
exit(0);
}
}*/
}
int getArguments(char** arguments, char* command){
int n_spaces = 0,i;
char *token;
token = strtok(command, " ");
/* Loop until we have gotten all of the tokens */
while (token) {
arguments = realloc (arguments, sizeof (char*) * ++n_spaces);
if (arguments == NULL){
printf("Memory allocation failed: token - %d\n", n_spaces);
exit (-1); /* memory allocation failed */
}
arguments[n_spaces-1] = token;
token = strtok (NULL, " ");
}
/* realloc one extra element for the last NULL */
arguments = realloc (arguments, sizeof (char*) * (n_spaces+1));
arguments[n_spaces] = 0;
/* print the result */
for (i = 0; i < (n_spaces+1); ++i)
printf ("arguments[%d] = %s\n", i, arguments[i]);
return strcmp("cd",arguments[0]);
}
int checkForDirectoryChange(char** arguments, int num_args){
return 0;
}
void getPath(char* pathBuffer){
size_t n;
n = confstr(_CS_PATH, NULL, (size_t) 0);
pathBuffer = malloc(n);
if (pathBuffer == NULL)
abort();
confstr(_CS_PATH, pathBuffer, n);
}

It is because getArguments() only reassigned the copy of pointer to pointer of characters inside itself. arguments in main() was not updated.
You should define getArguments() as
int getArguments(char*** arguments, char* command) {
/* ... */
while (token) {
*arguments = realloc (*arguments, sizeof (char*) * ++n_spaces);
if (*arguments == NULL){
printf("Memory allocation failed: token - %d\n", n_spaces);
exit (-1); /* memory allocation failed */
}
(*arguments)[n_spaces-1] = token;
token = strtok (NULL, " ");
}
/* ... */
}
And call it as the following inside main().
cd_requested = getArguments(&arguments, command);

Related

How can you copy a string to non-accessible memory?

char* argv[MAXARGS];
char* buf2=malloc(MAXLINE * sizeof(char));
strcpy(buf2, buf); //buf is string with some words
char* ptr = strtok(buf2, " ");
argv[0]=ptr;
strcpy(argv[0], ptr);
free(buf2);
Like above, I want to copy value of ptr to argv[0] but I can't use strcpy(argv[0],ptr) directly because accessing argv[0] without argv[0]=ptr cause segmentation fault. So I made code like above but then, after I free buf2, argv[0] becomes null. How can I copy ptr to argv without using =ptr in advance?
Code:
#define MAXARGS 128
#define MAXLINE 256
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
void eval(char* cmdline);
int parseline(char* buf, char** argv);
int main()
{
char cmdline[MAXLINE]; /* Command line */
char* ret;
while (1) {
/* Read */
printf("mini> ");
ret = fgets(cmdline, MAXLINE, stdin);
if (feof(stdin) || ret == NULL)
exit(0);
/* Evaluate */
eval(cmdline);
}
}
void eval(char* cmdline)
{
char** argv=malloc(MAXARGS*sizeof(char)); /* Argument list execve() */
char buf[MAXLINE]; /* Holds modified command line */
int bg; /* Should the job run in bg or fg? */
pid_t pid; /* Process id */
strcpy(buf, cmdline);
bg = parseline(buf, argv);
free(argv);
}
int parseline(char* buf, char** argv)
{
int argc; /* Number of args */
int bg; /* Background job? */
char* buf2=malloc(MAXLINE * sizeof(char));
while (*buf && (*buf == ' '))
buf++;
buf[strlen(buf) - 1] = ' ';/* Replace trailing '\n' with space */
strcpy(buf2, buf);
/* Build the argv list */
argc = 0;
char* ptr = strtok(buf2, " ");
printf("ptr: %s\n", ptr);
while (ptr != NULL) {
//argv[argc]=ptr;
strcpy(argv[argc++], ptr);
ptr = strtok(NULL, " ");
}
argv[argc] = NULL;
printf("0: %s\n", argv[0]);
/* Ignore blank line */
if (argc == 0)
return 1;
/* Should the job run in the background? */
if ((bg = (*argv[argc - 1] == '&')) != 0)
argv[--argc] = NULL;
free(buf2);
printf("0: %s\n", argv[0]);
if(argv[1]!=NULL)
printf("1: %s\n", argv[1]);
return bg;
}
Many errors in your code - I will not check everything only your issue.
Wrong allocation:
char** argv=malloc(MAXARGS*sizeof(char));
You need to allocate space for char pointers - you allocate for char. It is better to use objects instead of types.
char **argv=malloc(MAXARGS * sizeof(*argv));
Now you have allocated the memory for pointers - but not for char arrays to accommodate the strings. To directly copy to argv[n] you need to allocate this memory:
argv[n] = malloc(sizeof(**argv) * (strlen(ptr)+1));
if(argv[n]) strcpy(argv[n], ptr);
In your code you never check the result of malloc - you need to do it after every allocation/reallocation

free() errors and munmap_chunk errors when exiting a program

I wrote a program in C that tokenizes an input string, and when the user enters "exit", it exits the program.
It seems to tokenize the string correctly, however, when I exit the program, I get an error either about an "aborted (core dumped) error" about freeing memory, or a munmap_chunk error.
Here is the link to the picture of my output:
ErrorMessage
And here is my code for the program:
int main() {
/* Main Function Variables */
char *buf;
char *token;
size_t num_chars;
size_t bufsize = 2048;
int run = 1;
int tok_count = 0;
int cmp;
/* Allocate memory for the input buffer. */
buf = (char *) malloc(sizeof(char) * bufsize);
/*main run loop*/
while(run) {
/* Print >>> then get the input string */
printf(">>> ");
num_chars = getline(&buf, &bufsize, stdin);
cmp = strcmp(buf, "exit\n");
if (num_chars > 1) {
/* Tokenize the input string */
if (cmp != 0) {
/* Display each token */
while((token = strtok_r(buf, " ", &buf))) {
printf("T%d: %s\n", tok_count, token);
tok_count++;
}
}
/* If the user entered <exit> then exit the loop */
else {
run = 0;
break;
}
}
tok_count = 0;
}
/*Free the allocated memory*/
free(buf);
return 1;
}
What may be the problem here that is causing the free() errors and munmap_chunk errors?

Segmentation fault when using strcpy on double pointer

I'm pretty new to C, but have programmed a great deal in both Java and Python. So I got the basics going – however, C keeps hitting me with this Segmentation fault: 11 no matter how I wrap my head around my code. I suspect the problem may be that I'm accessing beyond the bounds of my array, namely in this part:
ordListe[i] = (char*)malloc(n);
strcpy(ordListe[i], ord);
For hours I've been at a loss how to solve this, so now I turn to you: what am I missing? I couldn't find many posts involving pointers to pointers out there with a similar problem, so i assume this will be of some help to others in the future too. Full function where the problem occurs:
char** split(char* s)
{
char* setning = (char*) malloc(strlen(s) + 1);
strcpy(setning, s); //Setning blir det samme som s, saa vi slipper aa roere s
printf("%s\n", setning); //TNB: Feilsoeking
char* ord = (char *) malloc(strlen(setning) * sizeof(char)); //Henter ut ordet
ord = strtok(setning, " "); //Henter foerste ord
printf("%s", ord);
int i = 0;
size_t n = 0;
char** ordListe = (char**) malloc(strlen(s) * sizeof(char)); //Lager en liste vi kan lagre verdiene i
ordListe[strlen(setning)+1] = NULL;
while(ord != NULL)
{
n = strlen(ordListe[i]) + 1;
ordListe[i] = (char*)malloc(n);
strcpy(ordListe[i], ord);
i++;
ord = strtok (NULL, " "); //Beveger den videre
}
free(setning);
return ordListe;
}
The purpose of the function is to split a string and store the individual parts in a pointer-to-pointer array and return said array.
Thanks in advance!
Here is one way to do it:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
/****************************************************************
**
*/
char **split(const char *s)
{
char *setning = NULL;
char *ord = NULL;
char **ordListe = NULL;
int elements = 0;
char **new;
/* Build non-const version of the input string. */
errno=0;
setning = strdup(s);
if(!setning)
{
fprintf(stderr, "strdup() reports: %d %s\n", errno, strerror(errno));
goto CLEANUP;
}
/* Parse the string into an array of strings. */
ord = strtok(setning, " ");
while(ord)
{
/* Increase the array of string pointers by one. */
errno=0;
new=realloc(ordListe, sizeof(char *) * (elements + 1));
if(!new)
{
fprintf(stderr, "realloc() reports: %d %s\n", errno, strerror(errno));
goto CLEANUP;
}
ordListe=new;
/* Append an allocated string to the end of the array of strings. */
ordListe[elements] = strdup(ord);
if(!ordListe[elements])
{
fprintf(stderr, "strdup() reports: %d %s\n", errno, strerror(errno));
goto CLEANUP;
}
++elements;
ord = strtok(NULL, " ");
}
/* Add a NULL termination value to the end of the array of strings. */
errno=0;
new=realloc(ordListe, sizeof(char *) * (elements + 1));
if(!new)
{
fprintf(stderr, "realloc() reports: %d %s\n", errno, strerror(errno));
goto CLEANUP;
}
ordListe=new;
ordListe[elements] = NULL;
CLEANUP:
/* Free the working copy of the string. */
if(setning)
free(setning);
/* Free everything if there was an error, and return NULL. */
if(errno)
{
while(elements)
free(ordListe[elements--]);
free(ordListe);
ordListe=NULL;
}
return ordListe;
}
/****************************************************************
** Program start.
*/
int main(int argC, char *argV[])
{
char **ordListe = NULL;
char **iter = NULL;
/* Split a string. */
ordListe=split("Now is the time for all good men to come to the aid of their country.");
if(!ordListe)
{
fprintf(stderr, "split() failed.\n");
goto CLEANUP;
}
/* Print each split-out string. */
iter = ordListe;
while(*iter)
{
printf("%s\n", *iter);
++iter;
}
CLEANUP:
/* Free the array of strings. */
if(ordListe)
{
iter = ordListe;
while(*iter)
{
free(*iter);
++iter;
}
free(ordListe);
}
return(0);
}

C: Losing strings when exiting functions

I'm trying to implement a basic shell, I have several functions within it that deal with strings, trying to find file names, implement something equivalent to *argv[] and so on.
I have strings in main(), which are passed to a function to be populated. Next the program returns to main(), which passes the strings to another function to be acted upon.
I was debugging with lldb and found that I was successfully populating the strings with the correct values in the first function but upon exiting the function, re-entering main() the output_str string was NULL again. I thought strings, since they point to space in memory would retain values. They seem to for all but one case, when flag = 1 in the code below.
I can't figure out what's happening as the values seem to only be lost after the final } of the function.
Edited to add complete code, hope it isn't too large.
The code works with say, cat input.txt but not with cat input.txt>output.txt when I try to redirect the output from stdout to a file
Thank you for your help in advance.
Here is the function .c file:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
void sig_handler(int signo)
{
if (signo == SIGINT)
{
fprintf(stdout, "\n");
fflush(stdout);
}
}
int check_redirect(char *line, int flag)
{
int n = 0;
if (line == NULL) return (flag);
else
{
do
{
if (line[n] == '>') flag = 1;
n++;
}while (line[n] != '\0');
}
return (flag);
}
void string_breakdown(char *line, char **output_str, int count, char* temp, char *filename, int *f, int *saved_stdout, int flag, int debug)
{
char *sep = " \n";
char *delim = ">\n";
if (line != NULL)
{
temp = strtok(line, delim);
while (temp != NULL)
{
output_str[count] = temp;
if (debug) fprintf(stderr, "1:%s\n2:%s\n3:%s\n", line, temp, output_str[count]);
count++;
output_str = realloc (output_str, (count + 1) * sizeof (char *) );
temp = strtok(NULL, delim);
}
if (flag)
{
count = 0;
strcpy(filename, output_str[1]);
output_str[1] = NULL;
*saved_stdout = dup(1);
*f = open(filename , O_WRONLY|O_CREAT|O_TRUNC, 0666);
dup2(*f, 1);
temp = strtok(*output_str[0], sep);
while (temp != NULL)
{
output_str[count] = temp;
//if (debug) fprintf(stderr, "1:%s\n2:%s\n3:%s\n", line, temp, output_str[count]);
count++;
output_str = realloc (output_str, (count + 1) * sizeof (char *));
temp = strtok(NULL, sep);
}
}
else
{
count = 0;
temp = strtok(line, sep);
while (temp != NULL)
{
output_str[count] = temp;
if (debug) fprintf(stderr, "1:%s\n2:%s\n3:%s\n", line, temp, output_str[count]);
count++;
output_str = realloc (output_str, (count + 1) * sizeof (char *));
temp = strtok(NULL, sep);
}
}
}
}
void com_exec(char *line, char **output_str, char *filename, int *f, int *saved_stdout, int flag, int debug)
{
char *command = malloc(sizeof(char *));
command = output_str[0];
char *name = "HOME";
int ret_val = 0;
pid_t child_pid;
int child_status;
if (command == NULL);
else if (strcmp("cd", command) == 0)
{
if (output_str[1] == NULL) output_str[1] = getenv(name);
ret_val = 0;
ret_val = chdir(output_str[1]);
if (ret_val) perror(NULL);
}
else
{
child_pid = fork ();
if (child_pid == 0)
{
if (debug)
{
system(line);
fprintf(stderr, "Post System Pre Exec\n1:%s\n2:%s\n3:%s\n", line, output_str[0], command);
sleep(2);
}
execvp(command, output_str);
if (flag)
{
close(*f);
dup2(*saved_stdout, 1);
close(*saved_stdout);
}
fprintf (stdout, "Unknown command\n");
exit (0);
}
else
{
if (flag)
{
close(*f);
dup2(*saved_stdout, 1);
close(*saved_stdout);
}
signal(SIGINT, sig_handler);
usleep(500000);
//Parent process waits for child to finish
if (debug) fprintf (stderr, "parent waiting\n");
wait(&child_status);
waitpid(child_pid, &child_status, 0);
signal(SIGINT, SIG_DFL);
}
}
Here is the functions .h file:
#ifndef SHELL_H_INCLUDED
#define SHELL_H_INCLUDED
void sig_handler(int signo);
int prompt(char *line, size_t len, ssize_t read);
int check_redirect(char *line, int flag);
void string_breakdown(char *line, char **output_str, int count, char* temp, char *filename, int *f, int *saved_stdout, int flag, int debug);
void com_exec(char *line, char **output_str, char *filename, int *f, int *saved_stdout, int flag, int debug);
#endif // LINKLAYER_H_INCLUDED
Below is main.c, where the function is called.
#include <unistd.h>
#include <time.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include "shell.h"
int main(void)
{
int debug = 0;
char *line = NULL;
size_t len = 0;
ssize_t read = 0;
int flag = 0;
int f = 0;
int saved_stdout = 0;
do
{
flag = 0;
//read = prompt(line, len, read);
char buffer[15];
time_t now = time(NULL);
strftime(buffer, 15, "[%d/%m %H:%M]", localtime(&now) );
fprintf(stdout, "%s # ", buffer);
signal(SIGINT, SIG_IGN);
read = getline (&line, &len, stdin);
signal(SIGINT, SIG_DFL);
flag = check_redirect(line, flag);
char **output_str = malloc(sizeof(char *));
int count = 0;
char* temp = NULL;
char *filename = malloc(sizeof(char *));
string_breakdown(line, output_str, count, temp, filename, &f, &saved_stdout, flag, debug); // function call of problem function
com_exec(line, output_str, filename, &f, &saved_stdout, flag, debug);
} while (read != EOF);
if (debug) fprintf(stderr, "parent exiting\n");
else fprintf(stdout, "\n");
return 0;
}
output_str = realloc (output_str, (count + 1) * sizeof (char *) );
This line re-assigns the value of the the local parameter variable output_str, but the new value in no way makes it back to the caller of the string_breakdown function - meaning that the pointer it has will probably be left dangling, and will cause problems when used ("undefined behavior", manifesting in strange program behavior or crashing).
You need to understand that within the function, output_str is a local variable. You can change its value, but that won't affect the value of any variable in the caller.
You call the function from main:
string_breakdown(line, output_str, count, temp, filename, &f, &saved_stdout, flag, debug); // The call of the above function
main also uses output_str as the variable name, but again, this is a different variable. One variable is local to main, the other is local to string_breakdown, even though they share the same name. Due to the realloc call above, the pointer value in main's output_str will most likely be invalid on return from string_breakdown, because it is not updated to point to the newly allocated memory. That's why you are "losing" the string values on return from the function - the output_str variable in main is no longer actually pointing to the array of strings, which has been moved to a different location via realloc.
Typically you resolve this kind of problem by adding another level of indirection, changing the output_str parameter from a char ** to a char ***:
void string_breakdown(char *line, char ***output_str, int count, char* temp, char *filename, int *f, int *saved_stdout, int flag, int debug)
and
(*output_str)[count] = temp;
and
*output_str = realloc (*output_str, (count + 1) * sizeof (char *) );
and so on. You need to adjust the call in main as well:
string_breakdown(line, &output_str, count, temp, filename, &f, &saved_stdout, flag, debug); // The call of the above function
Because you are passing a pointer to main's output_str variable, the called function is now able to modify its value.
You should also understand that string_breakdown as written modifies the string which the line parameter points to. That's because it uses strtok, and strtok replaces delimiters with nul bytes as it processes the string. So, it is odd that you pass this modified line buffer to com_exec after processing it with string_breakdown.
I get several warnings when I try to compile your code; main.c uses fprintf but doesn't #include <stdio.h>, and uses malloc but doesn't #include <stdlib.h>.
your realloc does nothing.
you mean *output_ptr = realloc....
actually it does something, but its really bad
this is also wrong
output_str[count] = temp;
and this
filename = output_str[1];
you need to distinguish - a pointer to your buffer, a pointer to the pointer to your buffer.
char * buffer = *output_str; // to remove the confusion
strcpy(&buffer[count], temp); // assigning pointers doesnt copy things
filename = buffer[1]; // is hat what you mean - filename is one char

sizeof(table)/sizof(table[0]) not working

H i am building a basic shell in c and i need to know the size of the array i am populating with user input. Here is the code.
/*
* Tp1.c
*
* Created on: 25 janv. 2014
* Author: shong
*/
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
void cd_handler(int argc, char *argv[]);
int lire(char *chaine, int longueur);
char** init_command(char *str);
int main(int argc, char *argv[]) {
//printf("La valeur de argc est: %d", argc);
while(1){
printf("Log710H2014%>");
char str[200];
lire(str, 200);
char** comms = init_command(str);
printf("%s", comms[1]);
if(strcmp(comms[0], "cd") == 0){
int commArgsC = sizeof(comms)/sizeof(comms[0]);
cd_handler(commArgsC, comms);
}else if (strcmp(comms[0], "exit") == 0){
exit(0);
}
}
}
}
void cd_handler(int argc, char *argv[]){
char cwd[256];
char * directory;
if(argc < 2){
directory = getenv("HOME");
}else if (argc == 2){
directory = argv[1];
}else{
exit(1);
}
if (chdir(directory) == -1) {
printf ("chdir failed - %s\n", strerror (errno));
}else{
if (getcwd(cwd, sizeof(cwd)) == NULL)
perror("getcwd() error");
else
printf("current working directory is: %s\n", cwd);
}
}
char** init_command(char* str){
char ** res = NULL;
char * p = strtok (str, " ");
int n_spaces = 0, i;
while (p) {
res = realloc (res, sizeof (char*) * ++n_spaces);
if (res == NULL){
exit (-1);
}
res[n_spaces-1] = p;
p = strtok (NULL, " ");
}
res = realloc (res, sizeof (char*) * (n_spaces+1));
res[n_spaces] = 0;
//print the result
//for (i = 0; i < (n_spaces+1); ++i)
//printf ("res[%d] = %s\n", i, res[i]);
//free the memory allocated
//free (res);
return res;
}
int lire(char *chaine, int longueur)
{
char *positionEntree = NULL;
if (fgets(chaine, longueur, stdin) != NULL)
{
positionEntree = strchr(chaine, '\n');
if (positionEntree != NULL)
{
//*positionEntree = '\0'; // On remplace ce caractère par \0
}
return 1;
}
else
{
return 0; // on renvoie 0 s'il y a eu une erreur
}
}
The problem is that sizeof(comms) always return 8, no matter the number of elements in comm.
comms is a pointer, so on a 64-bit machine it will have a size of 8 bytes. C has no knowledge about the size of what it points to. You'll have to return the size from the function that allocates the storage and keep track of it yourself.
The behavior sizeof is dependent on what type of variable it is applied to.
If the variable is a pointer, as in the question, sizeof simply evaluates to the size of the pointer type in bytes:
int *y; //y points to an int... maybe an array? Who knows?
printf("%d",sizeof(y)); //No idea how y has been allocated. Defaults to sizeof(int*)
If the variable was declared as an array, sizeof returns the size of the entire array. For instance:
int y[4]; //y is exactly four ints in memory
printf("%d",sizeof(y)); //sizeof knows this, and evaluates to sizeof(int)*4
This is why the sizeof(table)/sizeof(table[0]) would work for an array. However, it does not work pointers as demonstrated above. In short, passing an array as an argument destroys any information regarding how much data is in that array, and you must pass the size separately. This is referred to as "array decay."
The difference between pointers and arrays is very subtle. Most of the time, the two can be used interchangeably, but there are two critical differences:
The difference in the behavior of sizeof as discussed previously.
Arrays cannot be assigned as pointers can. This relates to the fact that they are of constant size. For instance:
char **table;
//table can be assigned different values....
table = NULL;
//...multiples times, if wanted
table = malloc(sizeof(char*)*20);
However,
//table is constant
char *table[20];
//it's individual elements can be assigned as usual...
table[0] = malloc(1);
//...but attempts to change where table points to will fail
table = NULL; //This will cause a compilation error.

Resources