subsequent printf statement ruining unrelated array - c

In the following code, the printed result for char array dir is gibberish.
However, if I comment out the indicated printf statement, the printed result is intelligible. What is going on here? Thanks. sing code blocks / gcc.
#include <stdio.h>
#include <string.h>
char* handle_input(int argc,char *argv[]){
char dir[200];
printf("Number of arguments: %d\n",argc);
if(argc<2) {
printf("No argument specified\n");
strcpy(dir,"Default argument");
}
else{
printf("Command line directory was specified\n");
++argv;
strcpy(dir,argv[0]);
}
strcat(dir,"_CAT");
return dir;
}
int main(int argc, char *argv[]){
char* dir;
dir = handle_input(argc,argv);
printf("This one messes it up!\n");
printf("%s\n",dir);
printf("DONE\n");
return 0;
}

In your handle_input function, you're returning a local array, which is a huge no-no; after the function ends, that array no longer exists, and what you return is just nonsense. This invokes undefined behavior later in your program. That printf call happens to overwrite the memory which previously belonged to the array. Without the printf call, that memory just happens to be intact, which is why it comes out intelligibly.
The right way to return an array is like this:
char* handle_input(int argc,char *argv[]){
char* dir = malloc(200 * sizeof(char)); // sizeof unnecessary for char,
// but it's a good habit to have
printf("Number of arguments: %d\n",argc);
if(argc<2) {
printf("No argument specified\n");
strcpy(dir,"Default argument");
}
else{
printf("Command line directory was specified\n");
++argv;
strcpy(dir,argv[0]); // This is unsafe! use strncpy instead
}
strcat(dir,"_CAT");
return dir;
}
Using malloc ensures that the memory allocated will continue to exist after the end of the function, and that you will no longer be causing undefined behavior. Note that arrays are somewhat "special"; you can return primitive values (int, char, etc) and structs without having this sort of behavior occur.

You are returning a local char dir[200] in the function handle_input, after the function exits, it's undefined behavior to access it.
Use dynamic memory allocation instead, like:
char* handle_input(int argc,char *argv[]){
char *dir = malloc(200);
//do the processing
return dir;
}
Remember to free it once it's out of use.

You are returning a local vasriable
Either
Use malloc (as you are in the C world with printf)
Pass in a pointer to be filled up

Related

Not printing outside of if statement

I am making my own version of make. I allow for some arguments to be passed via command line.
I am working on it in chunks. I am setting the fileName right now
I have the following code
int main(int argc, char *argv[]) {
char *fileName = NULL;
char fileFlag[2];
strcpy(fileFlag, "-f");
printf("%s\n", fileFlag);
if (argc == 1) {
fileName = (char *) malloc(sizeof("Makefile"));
strcpy(fileName, "Makefile");
printf("One arg %s\n", fileName);
}
printf("\n%s", fileName);
return 0;
}
When it runs I get the following output.
-f
One arg Makefile
Shouldn't it print another line?
The first problem is
strcpy(fileFlag, "-f");
fileFlag is one element short of the required space, you need to have 3 element-array to store "-f" along with the terminating null. In this case, as per the strcpy() behaviour,
The strcpy function copies the string pointed to by s2 (including the terminating null
character) into the array pointed to by s1. [...]
So, including the null-character, the size of the source is 3, so is needed for the destination also. Otherwise, you'll be accessing out of bound memory which invokes undefined behavior.
That said,
please see this discussion on why not to cast the return value of malloc() and family in C..
Always check for the success of malloc() before using the returned pointer.

Is it possible to add an argument to main by scanf?

I tried to add an argument to main by scanf. But it didn't work. The following is my program. My question is: what's wrong with this program? And is it possible to add an argument to main by scanf() instead of in the command line?
#include <stdio.h>
#include <errno.h>
int main(int argc, char* argv[]){
/*check if there is no argument, that is, argc!=2*/
if(argc != 2){
puts("Please enter an argument: ");
scanf("%s", &argv[1]);
printf("\nYou've entered argument: %s\n", argv[1]);
return 1;
}
printf("\nYou've entered argument: %s\n", argv[1]);
return 0;
}
Yes, code can effectively add arguments.
"The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination." C11dr ยง5.1.2.2.1 2
So this allows code to change argc and argv and change argv[0][0] (if argc > 0) - but wait, there's more...
Can code change the original elements of argv[], like argv[1], etc? That is an open question still hanging in SO here. So let us avoid that.
The way to change the contents of argv[] is to first create an alternate set argv_alt[] array and then assign argv_alt --> argv.
#include <stdio.h>
int main(int argc, char *argv[]) {
// Assume argc == 1
printf("%d '%s'\n", argc, argv[0]);
char a[3][10] = { "abc", "def", "fgh" };
char *argv_alt[] = { a[0], a[1], a[2], NULL };
argc = 3;
argv = argv_alt;
printf("%d '%s' '%s' '%s'\n", argc, argv[0], argv[1], argv[2]);
return 0;
}
Argv is allocated by the system when the user types in her arguments. If there wasn't arguments you cannot use the position 1 on that array. Although, as pointed out on the comments, you shouldn't do the way you are willing to, you could scanf arguments if you declare your own local variable.
The %s specifier in scanf expects that you pass in a pointer which points to space that has already been allocated and is big enough to hold whatever will be read.
Instead you pass in a pointer which points to an area where another pointer is stored. This causes undefined behaviour because the pointer you pass in has the wrong type.
It's not possible to extend the length of the argv array. In fact, writing to argv[n] probably causes undefined behaviour anyway.
Instead you should just read into a variable inside main.

Pointer to a Pointer in C

I am writing a below Pro*C program and I am getting core dump error, could someone please help me what I am doing wrong. I am new to C
int main(int argc,char *argv[])
{
char inputpath1[300]="";
char inputpath2[300]="";
gets(inputpath1);
gets(inputpath2);
ExtractCmpFiles(inputpath1,inputpath2); //contains fullpath with file
return 0;
}
void ExtractCmpFiles(char *inputpath1,char *inputpath2)
{
int i=0;
char *strings[2];
strings[0]=malloc(sizeof(inputpath1)+1);
strcpy(strings[0],inputpath1);
strings[1]=malloc(sizeof(inputpath2)+1);
strcpy(strings[1],inputpath2);
printf("Your files are:\n%s\n%s\n",strings[0],strings[1]);//i am getting output here
char **holder='\0';
char ioarea[4096];
for(i=0;i<2;i++)
{
inFile=fopen(strings[i],"r");
if(!inFile)
{
fprintf(stderr,": Open failure for output file:");
fprintf(stderr,strings[i]);
fprintf(stderr,"\n");
}
holder=&strings[i];
holder=strrchr(strings[i],'/'); //checking the address of '/' to get only filename
holder++; //incrementing pointer
printf("your holder is: %s\n",*holder);
if(strncmp(holder,"bills",5)==0) //checking value from the pointer address is "bills" or not
{
//do as you wish
}
}
}
output:
/your/path/bills.cmp
/your/path/bill.cmp
Thank you all. I have modified the function as per suggestions, but still I am getting core dump error
Adding modified function:
void ExtractCmpFiles(char *inputpath1,char *inputpath2)
{
char *strings[2];
strings[0]=(char*)malloc(strlen(*inputpath1)+1);
strcpy(strings[0],inputpath1);
strings[1]=(char*)malloc(strlen(*inputpath2)+1);
strcpy(strings[1],inputpath2);
printf("Your files are:\n%s\n%s\n",strings[0],strings[1]);
char *holder=NULL;
char ioarea[4096];
int i=0;
for(i=0;i<2;i++)
{
inFile=fopen(strings[i],"r");
if(!inFile)
{
fprintf(stderr,": Open failure for output file:");
fprintf(stderr,strings[i]);
fprintf(stderr,"\n");
}
holder=strings[i];
holder=strrchr(strings[i],'/');
printf("i=%d --- %s\n",i,strings[i]); //when i=0 it is giving output then it is giving coredump
printf("your holder1 is: %s\n",holder);
holder++;
printf("your holder2 is: %s\n",holder);
if(strncmp(holder,"custbills",9)==0)
{
//do something
}
else
{
//do something
}
fclose(inFile);
}
The variable holder is a pointer to a pointer to char, and you assign to it the result of strrchr, a function that returns a pointer to char.
That will make holder no longer point to the array entry, so when you do holder++ it points somewhere else completely which leads to undefined behavior when you dereference holder. You then continue to pass holder to strncmp which again will give you undefined behavior.
The holder variable is not a character either, so you should not initialize it as one. If you want to initialize it you should initialize it to point to NULL.
The things mentioned above should make the compiler shout warnings at you.
Also, as noted in a comment by Cool Guy, if you want to get the length of a string you should use strlen. When you use sizeof you get the size of the pointer and not what it points to.
strings[0]=(char*)malloc(strlen(inputpath1));
strings[1]=(char*)malloc(strlen(inputpath2));
...
char *holder=NULL;
...
fclose(inFile);

Splitting a string with strtok() goes wrong

I'm trying to get input from the user while allocating it dynamically and then "split" it using strtok.
Main Questions:
Im getting an infinite loop of "a{\300_\377" and ",".
Why do i get a warning of "Implicitly declaring library function "malloc"/"realoc" with type void"
Other less important questions:
3.i want to break, if the input includes "-1", how do i check it? As you can see it breaks now if its 1.
4.In the getsWordsArray() i want to return a pointer to an array of strings. Since i dont know how many strings there are do i also need to dynamically allocate it like in the getInput(). (I dont know how many chars are there in each string)
int main(int argc, const char * argv[])
{
char input = getInput();
getWordsArray(&input);
}
char getInput()
{
char *data,*temp;
data=malloc(sizeof(char));
char c; /* c is the current character */
int i; /* i is the counter */
printf ("\n Enter chars and to finish push new line:\n");
for (i=0;;i++) {
c=getchar(); /* put input character into c */
if (c== '1') // need to find a way to change it to -1
break;
data[i]=c; /* put the character into the data array */
temp=realloc(data,(i+1)*sizeof(char)); /* give the pointer some memory */
if ( temp != NULL ) {
data=temp;
} else {
free(data);
printf("Error allocating memory!\n");
return 0 ;
}
}
printf("list is: %s\n",data); // for checking
return *data;
}
void getWordsArray(char *input)
{
char *token;
char *search = " ,";
token = strtok (input,search);
while (token != NULL ) {
printf("%s\n",token);
token = strtok(NULL,search);
}
}
EDIT:
i noticed i forgot to "strtok" command so i changed it to token = strtok(NULL,search);
I still get wierd output on the printf:
\327{\300_\377
Change:
int main(int argc, const char * argv[])
{
char input = getInput();
getWordsArray(&input);
}
to:
int main(int argc, const char * argv[])
{
char *input = getInput();
getWordsArray(input);
}
with a similar to the return value of getInput():
char *getInput()
{
// ...
return data;
}
In your code, you were only saving the first character of the input string, and then passing mostly garbage to getWordsArray().
For your malloc() question, man malloc starts with:
SYNOPSIS
#include <stdlib.h>
For your getchar() question, perhaps see I'm trying to understand getchar() != EOF, etc.
Joseph answered Q1.
Q2: malloc and realoc returns type void *. You need to explicitly convert that to char *. Try this:
data = (char *) malloc(sizeof(char));
Q3: 1 can be interpreted as one character. -1, while converting to characters, is equivalent to string "-1" which has character '-' and '1'. In order to check against -1, you need to use strcmp or strncmp to compare against the string "-1".
Q4: If you are going to return a different copy, yes, dynamically allocate memory is a good idea. Alternatively, you can put all pointers to each token into a data structure like a linked list for future reference. This way, you avoid making copies and just allow access to each token in the string.
Things that are wrong:
Strings in C are null-terminated. The %s argument to printf means "just keep printing characters until you hit a '\0'". Since you don't null-terminate data before printing it, printf is running off the end of data and just printing your heap (which happens to not contain any null bytes to stop it).
What headers did you #include? Missing <stdlib.h> is the most obvious reason for an implicit declaration of malloc.
getInput returns the first char of data by value. This is not what you want. (getWordsArray will never work. Also see 1.)
Suggestions:
Here's one idea for breaking on -1: if ((c == '1') && (data[i-1] == '-'))
To get an array of the strings you would indeed need a dynamic array of char *. You could either malloc a new string to copy each token that strtok returns, or just save each token directly as a pointer into input.

Buffer Overflow issue in environment variable replacement scheme

Whenever the environment variable's value is larger than its key in this method, I get a buffer overflow. Target is part of a dynamically allocated two dimensional array for tokens. Whenever I replace the token that's an environment variable with a value longer than it, it flows into the next token. I've tried adding a realloc to try and fix it, but it doesn't work or leads to a segfault.
If anyone has any suggestions or can point me at something I"m overlooking, I'd greatly appreciate it, because I have a feeling I'll be kicking myself when I find it out anyway.
The method is:
void envReplace(ENV *evlist, char *Target)
{
if (Target[0] == '#')
{
memmove(Target, Target+1, strlen(Target));
for(q = 0; q<16; q++)
{
if(evlist[q].envVariable!=NULL)
{
if(strcmp(Target, evlist[q].envVariable)==0)
{
//this is where I'd add the realloc as realloc(Target, strlen(evlist[q].Value))
strcpy(Target, evlist[q].Value);
return;
}
}
}
printf("Variable not found\n");
}
else
{
printf("A value that didn't start with # was an argument\n");
return;
}
}
The data structure ENV is:
typedef struct envStorage
{
char *envVariable;
char *Value;
}ENV;
You can pass a pointer to a pointer, like this, and then you can call realloc() inside the function, modifying the original pointer.
void func (char **to_change) {
// Changes the char *target in main()
*to_change = (char *) realloc(*to_change, 20);
sprintf (*to_change, "Blablablablabla\n");
}
int main (int argc, char **argv) {
char *target = (char *) malloc (10);
func(&target);
printf(target);
free(target);
}
In this example, func() writes to the original pointer char *target in the main() function.
What happens in your code, is that you realloc() and assign to a copy of the pointer. The pointer is copied when you call envReplace(). When this function returns, the original pointer contains the old memory address, which is no longer valid allocated memory (it was freed by realloc()).

Resources