C: Losing strings when exiting functions - c

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

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

I'm writing a shell in C and I am having trouble with pointers to char arrays in a struct

When I run my code the first printParams() call works perfectly. But every call after fork() the struct loses all of its char array values. I'm not that knowledgeable of pointers, but I can tell that the root of this problem is probably pointer-based. For example, the first printParams() will print out all of the values assigned in the Parse() function. But after the fork(), all of the integer values such as background and argumentCount are displayed but none of the string values associated with inputRedirect or the string values held in the vectorArguments array.
![Here is a photo of my output]]1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "parse.h"
void printParams(Param_t * param);
struct PARAM
{
char *inputRedirect; /* file name or NULL */
char *outputRedirect; /* file name or NULL */
int background; /* ethier 0 (false) or 1 (true) */
int argumentCount; /* number of tokens in argument vector
*/
char *argumentVector[MAXARGS]; /* array of String */
};
typedef struct PARAM Param_t;
int main(int argc, char *argv[]){
int i;
int debug;
pid_t pid;
if(argc>1){
if(!strcmp(argv[1], "-debug"))
debug = 1;
}
Param_t * testParam = Parse();
if(debug == 1){
printParams(testParam);
}
pid = fork();
printParams(testParam);
if(pid == 0){
exit(1);
}
return 0;
}
void printParams(Param_t *param)
{
int i;
printf("InputRedirect: [%s]\n", (param->inputRedirect != NULL) ? param-
>inputRedirect: "NULL");
printf("OutputRedirect: [%s]\n", (param->outputRedirect != NULL) ?
param->outputRedirect: "NULL");
printf ("Background: [%d]\n", param->background);
printf ("ArgumentCount: [%d]\n", param->argumentCount);
for (i = 0; i < param->argumentCount; i++)
printf("ArgumentVector[%2d]: [%s]\n", i, param->argumentVector[i]);
}
Param_t* Parse(){
char *toke[MAXARGS];
int i = 0;
char str[MAXSTRLENGTH];
int j;
int k=0;
Param_t* testParam = malloc(sizeof(Param_t));
testParam->argumentCount = 0;
printf("Enter your commands:\n");
fgets(str, MAXSTRLENGTH, stdin);
toke[i] = strtok(str, " ");
//Tokenizes the user input into the toke array
while(toke[i] != NULL){
//printf("%s\n", toke[i]);
++i;
toke[i] = strtok(NULL, " ");
}
i=0;
char c;
while(toke[i] != NULL){
c = toke[i][0];
if(c == '<')
{
for(j=0; j<strlen(toke[i]); ++j ){
toke[i][j] = toke[i][j+1];
}
testParam->inputRedirect = toke[i];
}
else if(c == '>')
{
for(j=0; j<strlen(toke[i]); ++j ){
toke[i][j] = toke[i][j+1];
}
testParam->outputRedirect = toke[i];
}
else if(c == '&')
{
testParam->background = 1;
//background
}
else
{
testParam->argumentVector[k] = toke[i];
k++;
//save as cmd vector
}
++i;
}
testParam->argumentCount = k;
return testParam;
}
The reason you loose all char * values is because strtok() function doesn't create buffer. Basically all your char* consist of an address pointing into str variable you read with fgets(). The str variable has scope only to end of Parse() function.
Solution for this:
Replace:
testParam->inputRedirect = toke[i];
with:
testParam->inputRedirect = malloc(MAXSTRLENGTH);
memset( testParam->inputRedirect, 0, MAXSTRLENGTH);
memcpy( testParam->inputRedirect, toke[i], strlen(toke[i]) );
But please note, that this leads to memory leak since there is no free().
Sugestion:
Create static instance of structure in main and give its pointer to Parse function.
Param_t testParam;
Parse( &testParam );
Let the Parse function fill it. And at the end of main call free for all char * buffers inside testParam

System call execve does not return with ls function

I am asked to implement my own shell for an Operating System class.
My shell runs every commands fine, except ls that won't return on execve, which is weird because cd, cp, mv, and all the others main commands are returning okay.
ls is still displaying the right output (the list of files in the folder), but just keep running after (execve hangs and needs a carriage return to finish).
All the options like -l, -a are also working correctly, with the same issue.
EDIT: I modified my code in order to completely avoid any memory leaks (I used valgrind to track them), added some comments so you can see what's going on, but ls is still not returning. Here is the updated version:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAXPATHLEN 40
#define MAXSIZE 100
#define MAXARGS 10
static char cwd[MAXPATHLEN];
typedef void (*sighandler_t)(int);
void handle_signal(int signo);
void parse_command(char *command, char **arguments);
int main(int argc, char *argv[], char *envp[])
{
int status;
char *command;
char **arguments;
signal(SIGINT, SIG_IGN);
signal(SIGINT, handle_signal);
while(1) {
//Allocating memory
command = calloc(MAXSIZE, sizeof(char));
arguments = calloc(MAXARGS, sizeof(char *));
//Print shell name and cwd
getcwd(cwd,MAXPATHLEN);
printf("[MY_SHELL]:%s$ ", cwd);
parse_command(command, arguments);
//Displays command and arguments
printf("Command is %s\n", command);
int i;
for(i=0; arguments[i] != NULL; ++i){
printf("Argument %d is %s\n", i, arguments[i]);
}
//Fork exec code
if (fork() != 0){
waitpid(1, &status, 0);
} else{
execve(command, arguments, 0);
}
free(command);
for (i=0; arguments[i] != NULL; ++i) {
free(arguments[i]);
}
free(arguments);
}
return 0;
}
void handle_signal(int signo)
{
getcwd(cwd,MAXPATHLEN);
printf("\n[MY_SHELL]:%s$ ", cwd);
fflush(stdout);
}
void parse_command(char *command, char **arguments){
char buf[MAXSIZE];
char env[MAXPATHLEN];
char *tmp;
//Initiate array values to avoid buffer overflows
memset(buf, 0, sizeof(buf));
memset(env, 0, sizeof(env));
//Read command and put it in a buffer
char c = '\0';
int N = 0; //Number of chars in input - shouldn't be more than MAXSIZE
while(1) {
c = getchar();
if (c == '\n')
break;
else{
if (N == MAXSIZE)
break;
buf[N] = c;
}
++N;
}
//Extract command name (e.g "ls"), fetch path to command, append it to command name
tmp = strtok(buf, " ");
strcpy(env, "/bin/");
size_t len1 = strlen(env);
size_t len2 = strlen(tmp);
memcpy(command, env, len1);
memcpy(command + len1, tmp, len2);
//Extracts arguments array: arguments[0] is path+command name
arguments[0] = calloc(strlen(command) + 1, sizeof(char));
strcpy(arguments[0], command);
int i = 1;
while(1){
tmp = strtok(NULL, " ");
if (tmp == NULL)
break;
else{
arguments[i] = calloc(strlen(tmp) + 1, sizeof(char));
strcpy(arguments[i],tmp);
++i;
}
}
}
EDIT 2: This seems to have something to do with STDIN (or STDOUT): similarily than ls, cat makes execve hangs after executing, and I need to carriage return to have my shell line [MY_SHELL]current_working_directory$: line back. Any thoughts on why it is the case ?
In your code, in parse_command() function, you're doing
bzero(arguments, sizeof(char) * MAXARGS);
but at that point of time, arguments is not initialized or allocated memory. So essentially you're trying to write into uninitialized memory. This invokes undefined behaviour.
Same like that, without allocating memory to arguments, you're accessing arguments[0].
Note: As I already mentioned in my comments, do not cast the return value of malloc() and family.
C uses pass by value. That means that after the call to parse_command the value of arguments will still be undefined, since any assignments were made to the local copy. Instead of becoming a three-star programmer I would recommend that you have parse_command return the argument list instead:
char **parse_command(char *command){
char **arguments = malloc(...);
...
return arguments;
}
And in main:
arguments = parse_command(command);
Also look at Sourav Ghosh's answer as he points out some other bugs.

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

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);

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