Free allocated string after strcat - c

According to the Allocate string (char*) in another function I have now code like this:
void someFunction(char** string, char** argv) {
*string = (char*)malloc(strlen(argv[2]) + 1);
strcpy(*string, argv[2]);
strcat(*string, ".txt"); //works fine without this
}
int main(int argc, char** argv) {
char *string;
char *string2;
someFunction(&string,argv);
printf("%s",string);
free(string); // freezes here due the strcat
}
After adding strcat to the code from the linked question, it freezes when I try to free my string.

You didn't allocate enough space for the resulting concatenated string; when you write past the end you invoke undefined behavior (in this case, likely heap corruption). Change the malloc to allocate strlen(argv[2]) + strlen(".txt") + 1 so you have a large enough buffer to hold the whole string.

Function someFunction has a bug. It does not allocate enough memory to append
".txt".
It could look the following way
void someFunction(char** string, char** argv) {
*string = (char*)malloc(strlen(argv[2]) + 1 + 4 );
strcpy(*string, argv[2]);
strcat(*string, ".txt"); //works fine without this
}
However in any case the design of the function is bad. It uses magic number 2 in the expression argv[2] . If the function deals with argv[2] then there is no sense to pass as an argument the whole array pf pointers argv. You should just pass argv[2]. Moreover it uses parameter string by reference but does not free the memory that the parameter can point to. So its interface is confusing.
You can use the function shown in my answer to the question
Safe way to concat two strings in C
The function could be called like
char *string = getConcatString( argv[2], ".txt" );
if ( string ) puts( string );
free( string );

Related

Allocate memory to a specific "string"

I just started to learn memory management in C, and I didn't understand something. I want to allocate memory to a buffer that holds 12 bytes. which is the exact size of Hello World! without null terminator.
Then I want to append a string to the current string with strcat, and of course I cannot do that because I will get core dumped error.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char mystr[12] = "Hello World!";
# allocate memory to mystr?
char *ptr = (char*) malloc(13 * sizeof(char));
strcat(mystr, "Hello");
return 0;
}
So, I don't know how can I allocate memory to the mystr variable if malloc doesn't take any other arguments except the target size.
I don't know how can I allocate memory to the mystr variable if malloc doesn't take any other arguments except the target size.
It is not possible to allocate extra memory to an array. Instead, what you want to do is allocate a new block of memory, copying the original string into the beginning of that memory (strcpy), then append the rest (strcat):
char *p = (char*) malloc((12 + 5 + 1) * sizeof(char));
strcpy(p, myptr);
strcat(p, "Hello");
12 for the first string, plus 5 for the second, plus one for the null-terminator.
Of course, since you know the final size, you could also simply allocate a big enough array instead of using malloc (and you can also use memcpy, too).
The problem should be that a string in C always end with a NULL character (also noted '\0'), so your string is actually 13 characters long. (That character is always automatically added with string literals and serves at telling where the string stops, because a string doesn't have a fixed length.)
So the strcat tries to read the string Hello world! followed by garbage (since the null-terminator is not included in the string).
P.S.: the error is not the core dumped but the Segmentation fault that precedes it, and this tells you that you are trying to change something in a segment you are not supposed to change (or execute/read something you are not supposed to -- this is a security feature).
Edit: after modifying the string mystr, you also need to change the length you allocate (in the malloc: use 13 * sizeof(char), or more simply here in this case sizeof(mystr)).
P.S. 2: also comments in C are started by //, not # (those are preprocessor directives).
you cant change the size of the array. mystr has to be also dynamically allocated.
int main(int argc, char const *argv[])
{
const char *ptr = "Hello World!";
const char *ptr2 = "hello";
char *mystr = malloc(strlen(ptr)+1);
strcpy(mystr, ptr);
mystr = realloc(mystr, strlen(mystr) + strlen(ptr2) + 1);
strcat(mystr, ptr2);
return 0;
}

Why should I declare a String as a fixed-size array

I have this program:
#include<stdio.h>
void copy_string(char string1[], char string2[]){
int counter=0;
while(string1[counter]!='\0'){
string2[counter] = string1[counter];
counter++;
}
string2[counter] = '\0';
}
int main() {
char* myString = "Hello there!";
char* myStringCopy;
copy_string(myString, myStringCopy);
printf("%s", myStringCopy);
}
My question is, why isn't it working unless I declare myStringCopy as a fixed-size variable (char myStringCopy[12];)? Shouldn't it work if I add a \0 character after the copy as I'm doing?
It can work by doing char* myStringCopy as long as you allocate memory space for it.
for example
char* myStringCopy
myStringCopy = malloc(sizeof(char) * (strlen(myString)+1))
I might be mistaken about the +1 but I think it is like this.
char myStringCopy[12]; tells the compiler to create an array of 12 char. When myStringCopy is passed to copy_string, this array is automatically converted to a pointer to its first element, so copy_string receives a pointer to the characters.
char *myStringCopy; tells the compiler to create a pointer to char. The compiler creates this pointer, including providing memory for it, but it does not set the value of the pointer. When this pointer is passed to copy_string, copy_string does not receive a valid value.
To make char *myStringCopy; work, you must allocate memory (which you can do with malloc). For example, you could use:
char *myStringCopy;
myStringCopy = malloc(13 * sizeof *myStringCopy);
if (myStringCopy == NULL)
{
fprintf(stderr, "Error, the malloc did not work.\n");
exit(EXIT_FAILURE);
}
Also, note that 12 is not enough. The string “Hello there!” contains 12 characters, but it also includes a terminating null character. You must provide space for the null character. char myStringCopy[12]; appeared to work, but copy_string was actually writing a thirteenth character beyond the array, damaging something else in your program.
The problem is that you don't have room for mystringCopy
You need to reserve space first:
char* myString = "Hello there!";
char* myStringCopy = malloc(strlen(myString) + 1);
char* myStringCopy;
This is only pointer to char*. You must first allocate memory for myStringCopy, before start copy. When you declare it like this:
char myStringCopy[12];
compiler allocate enough memory in stack.

unable to get filename from argv[1] in C

I'm trying to make a program which makes a copy of the file you put in, only then with a reversed filename (eg. input.txt = txt.tupni).
I start my program with
int main(int argc, char **argv) {
When I use printf("%s",argv[1]) I can see the file name which has been put in. However, when I try to manipulate it I can't get it to work.
char name = argv[1] doesnt work,
neither does char name[] = argv[1] work
All I want is either a char array or a piece of malloc memory which has all of the characters.
argv is of type char **, so argv[1] is of type char *. So that's the type of the variable you want to assign this to.
char *name = argv[1];
You can't declare name as char [] and initialize it with a char *. Only a string literal may be used for initialization.
If you want to make a copy of the string rather than have another pointer to it, you can use strdup which allocates memory for the copied string and copies it over.
char *name = strdup(argv[1]);
Don't forget to free it when you're done with it.
You need to use a function like strcpy to accomplish this, as well as know the string length.
Here's what you do:
int len = strlen(argv[1])
char *buffer = (char*)malloc(len + 1);
if(buffer != NULL)
{
strcpy(buffer, argv[1]);
// copy the file etc.
}

Dynamically allocated string from command line argument

I'm looking to process a string passed via a command line argument with a for loop in C. I'm wondering if this would be the correct way.
main(int argc, char * argv[])
{
char * somestring;
somestring = malloc( (strlen(argv[1]) + 1) * sizeof(char) );
somestring = argv[1];
...
}
or would C allocate the appropriate memory if I did:
char * somestring;
somestring = argv[1];
If you want to copy an argument in your own allocated memory then you have to write
int main(int argc, char * argv[1])
{
char * somestring;
somestring = malloc( strlen( argv[1] ) + 1 );
strcpy( somestring, argv[1] );
...
}
otherwise statement
somestring = argv[1];
results in a memory leak.
Also do not forget to free the memory when it will not be needed any more.
Take into account that though this record
int main(int argc, char * argv[1])
is valid it is better to write
int main(int argc, char * argv[])
because your intention by specifying char * argv[1] is not clear
If you need to preserve a transient string then yes you need to allocate memory, copy it into the new buffer (via strcpy-like function) and latter deallocate that buffer.
But in this case, the command line arguments are not transient. They are available for the whole lifetime of the process. Therefore it is enough to just remember the pointer to them. So something like this would be enough:
const char* firstParameter = nullptr;
int main(int argc, char* argv[])
{
if (argc > 1) firstParameter = argv[1];
}
A good way would be allocating the memory for the pointer and use strcpy function to copy the contents.
For example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char * argv[])
{
char *somestring;
if(argv[1] == NULL)
{
puts("Argument 1 is not specified.");
exit(1);
}
somestring = malloc( strlen(argv[1])+1 );
strcpy(somestring, argv[1]);
printf("%s\n",somestring);
return 0;
}
Also before allocating the memory for pointer, first check if argv[1] is not NULL.
Fisrt of all this is a wrong way of copying a string into another string.
You have done memory allocation correcly but your method of copying a string into another is wrong. You have allocated memory for string and collected its address into somestring. Now you are assigning argv[1] to it which is address of command line argument vector which is 2D array actually. So you should use strcpy() to copy string.
Or if you want just base address of string use char pointer instead and assign argv[1] to it. But it is of no use.
P.S. passing command line argument like you are doing is not recommended as all arguments are stored in argument vector argv which is 2D array. So if you are passing only one string then it is okay but if you are passing more than one strings then use char **argv instead.

How to memcpy() from argv[]?

I want to copy string from argv[0] but I don't know how to get the size of argv[0].
How to do this?
int main(int argc, char* argv[])
{
char str[20];
if(argc>0)
memcpy(str, argv[0], sizeof(argv[0]));
}
Since argv[0] is a string, use strlen.
#include <string.h>
size_t length = strlen (argv[0]) + 1;
memcpy (str, argv[0], length);
By the way, you could also use strcpy, which is more suitable for strings.
#include <string.h>
strcpy (str, argv[0]);
In every case, in order to make sure that your copy won't overflow, you should check whether the size of str is sufficient.
if (sizeof str >= length)
{
/* Do the copy. */
}
else
{
/* Report an error, or use dynamic allocation. */
}
You can use strdup() if your platform supports it. this makes your code more simple
int main(int argc, char* argv[])
{
char *str = NULL;
if(argc>0) {
str = strdup(argv[0]);
}
.......
// when the str became useless then free it
free(str);
........
}
You need to use strlen. If you were to use sizeof, then you would get the size of the char*.
To copy the string, you should use strcpy or just assign to another char*. Better yet, use strncpy in conjunction with a size (the size of the destination - 1) to prevent buffer overflows into str. The -1 is to account for the null-terminating character (\0). Don't forget about this character! The problem becomes if strlen returns 20. Then it will drop the \0. You should also read up on secure use of strcpy and you can read more about strncpy here.
OR, you can do this and it makes everything I said moot:
const char* arg1 = argv[0];
which would make strlen pointless in this case.
char* argv[] is an array of pointers (char*) so sizeof(argv[0]) is equal to sizeof(char*).
You could either use strlen:
memcpy(str, argv[0], strlen(argv[0]) + 1); // +1 because of '\0' at the end
or yet even better you could use strcpy:
strcpy(str, argv[0]);
but note that the length of the argv[0] might be greater than the size of your destination buffer (str) so you should either check the size of argv[0] before copying it.
You could also use strcnpy to copy only specified amount of characters, but in that case be very careful, because if there is no \0 in first 20 characters of argv[0], you'll have to terminate your string explicitly.
If your Cxx is >= C99
than you can do it in this way:
int main(int argc, char* argv[])
{
int len = (argc>0) ? strlen(argv[0]) : 0;
char str[len+1];
if (argc>0)
memcpy(str, argv[0], len+1);
}
I suggest to you to use pointer and allocate memory depending of the length of argv[0]:
int main(int argc, char* argv[])
{
char *str = NULL;
if(argc>0) {
int len = strlen(argv[0])
str = malloc((len+1) * sizeof(char))
memcpy(str, argv[0], (len+1));
}
.......
// when the str became useless then free it
free(str);
........
}
To summarise, because there's a lot of confusion and bad advice here:
The answer to your question in the narrowest sense is that you can find out the length of strings using strlen (sizeof returns the size of the data type in bytes, which for strings in char*, which (on a typical modern machine) will be either 4 (on 32-bit systems) or 8 (on 64-bit systems) regardless of the length of the string), but...
Make sure this is something you need to be doing in the first place. If you don't intend to change the string, there's no reason to copy it. If you do intend to change it, you only need to copy it if you also want to preserve the old value, because the argv strings are mutable (as per the standard).
If you either don't intend to change it or don't need the old value, but you still want another variable for some reason (readability, presumably), you should declare that variable as a pointer rather than an array and just assign to it:
char *str = argv[0];
If you're sure you do want to copy the string, you should not be using memcpy for this. You should be using strcpy, and you should be sure your new string is big enough to hold argv[0]. If you're using C99, you can do this easily:
char str[strlen(argv[0]) + 1];
strcpy(str, argv[0]);
If you're using an older standard, you will need to allocate memory dynamically:
char *str = malloc(strlen(argv[0]) + 1);
strcpy(str, argv[0]);
If you're on a POSIX system, you can shorten that by using strdup:
char *str = strdup(argv[0]);
If you're using malloc or strdup, remember that you need to free your memory manually when you're done with it.
(You don't need to check if argc > 0 in any case, by the way; the standard guarantees that argv[0] is either the program name or a zero-length string (that is, argv[0][0] is '\0').)
If you can't get away from using a fixed-length buffer, you can use strncpy if you remember to nul-terminate the resulting string manually and it's acceptable that your string is truncated if it is longer than the buffer:
char str[20];
strncpy(str, argv[0], 20); /* or 19, it doesn't matter. */
str[19] = '\0';
I think that's everything.
There is such a flood of bad advice here, I have no idea why, this question is not complicated rocket science, but rather beginner level programming.
You check that there is an argument in argv[0], but formally there will always be at least one argument passed to main. The check against argc > 0 is to be regarded as defensive programming, but extra error checks are never bad.
You need to check against buffer overflows before copying the contents of an unknown buffer.
#include <string.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
if(argc == 0)
{
// unexpected error
}
size_t len = strlen(argv[0]);
char* str = malloc(len * sizeof(char) + 1);
if(str == NULL)
{
// no memory, error
}
strcpy(str, argv[0], len);
...
free(str);
}
And that's it.
strdup is bad advice because it isn't C standard and therefore not portable. It is also a completely superfluous function.
strncpy is bad advice, it was never intended as a secure version of strcpy. It is an old legacy function for handling records in dinosaur unix systems. It is much more dangerous than strcpy because it is easy to forget the null termination. There is never a reason to use strncpy in a modern C program. For some reason unknown, there is a lot of programmers who have been brainwashed into using strncpy as a guard against buffer overflows. Don't do this, the correct way is to ensure that the buffer is large enough before using strcpy/memcpy.

Resources