Using realloc with char* [duplicate] - c

This question already has answers here:
Proper way to copy C strings
(4 answers)
Closed 2 months ago.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *cp;
cp = (char *)malloc(10 * sizeof(char));
cp="kerem";
//strcpy(cp, "kerem");
printf("%s",cp);
cp=(char *)realloc(cp,30 * sizeof(char));
//strcpy(cp, "kerem demir Aziz Kerem Demir");
cp= "kerem demir Aziz Kerem Demir";
printf("%s",cp);
//free(cp);
return 0;
}
While using the strcpy function, I can copy the pointer string without any problems, but; When I do this using char * I get this error: realloc(): invalid pointer

There are a few problems in this code:
It seems you expect cp="kerem"; to be copying the data to the location pointed to by cp, while in fact it just makes cp to point to the location of the string literal "kerem"
Having in mind the first bullet, you are calling realloc on a pointer to string literal which is not allowed
Even if we ignore the first two, the new size of cp would be 20, which is not sufficient to store the value you try to copy (even assuming you use strcpy instead of =).

The crucial problem is the line:
cp="kerem";
The string literals in C works more or less (*) like this:
static char _unnamed_[] = "kerem";
cp = _unnamed_;
Now the cp points to a memory that does not originate from a dynamic allocation via malloc/realloc and it cannot be an argument for realloc without invoking Undefined Behavior.
That is why strcpy is required because it copies the content of the memory to another memory pointed by cp. The value of the pointer cp does not change.
(*) string literals cannot be modified, moreover literal with the same content may share the storage.

Related

Why does malloc seemingly allow me to write over memory? [duplicate]

This question already has answers here:
How can I correctly assign a new string value?
(4 answers)
Closed 4 years ago.
Why does this not return a segmentation fault 11?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
char *test;
test = (char*) (malloc(sizeof(char)*3));
test = "foo";
printf("%s\n", test);
test = "foobar";
printf("%s\n", test);
return 0;
}
My outcome is
foo
foobar
I'm fairly new to C, but when I was compiling this using both gcc on mac and Windows Debugger on Windows 10, it doesn't crash like I expected.
My understanding is that by using (char*) (malloc(sizeof(char)*3)), I am creating a character array of length 3. Then, when I assign test to the string foobar I am writing to 6 array positions.
I'm left sitting here, staring at my apparently valid, runnable code scratching my head.
test = "foo";
Here you do not copy the string to the allocated memory, test no longer points to the allocated memory, instead it points to the string literal "foo". Same goes for "foobar". Also as pointed out in the comments the address of the allocated memory is lost and therefore it is a memory leak (since there is no way to retrieve the address of the memory).
If you want to copy a string to another destination you need to use strcpy or loop over every character.
If you write or read outside bounds of the allocated space you are invoking undefined behavior. That means that basicly everything can happen, also that it works.
Your program never writes to the location pointed to by the return from malloc(). All you've done with e.g. test = "foo"; is change what test points to, which by the way is a memory leak since you've then lost what malloc() returned.
To properly use the memory you allocated with malloc(), use strcpy(), snprintf(), etc.
Also, don't forget the null terminator in your C strings. To properly store e.g. "foobar" you need at least 7 bytes, not 6.
First thing is that you waste the memory allocated by malloc unnecessorily by storing the address of foo into that.
If you are going to point to string in code section then there is no need to allocate memory to the pointer.
When to allocate memory to pointer
e.g. when you intended to scan 'n' number of bytes from keyboard in pointer.
char *ptr,num_char;
scanf("%d",&num_char);
ptr = (char *)malloc(num_char*sizeof(char));
scanf("%s",ptr);

how to accept a char * in C using scanf() [duplicate]

This question already has answers here:
segmentation fault using scanf [duplicate]
(2 answers)
Closed 7 years ago.
I'm trying to input a word in the form of a char * in C
Such as :
char *inputText;
scanf("%s",inputText);
printf("This is your string %s",inputText);
I have tried with using
scanf("%s",&inputText);
As well
Each time I either get a compile error or Segmentation fault when I run it
"format '%s' expects type 'char *' but argument 2 has type 'char **'
I'm not sure if I'm missing something really simple but It's quite confusing.
My code depends on using char *
If theres a way to convert an easier input method into char * then can you show me that method?
You haven't initialized inputText so it's pointing to some random memory which you probably don't even own. Asking scanf write to that memory location results in undefined behavior.
You need to allocate memory for the pointer to point to:
char *inputText = malloc(amount_of_bytes_to_allocate);
Now inputText points to the allocated memory, and scanf can happily write to that memory location without a segfault. Remember that you must free(inputText) when you're done using the allocated memory.
But preferably, you wouldn't use dynamic memory (malloc) in this case since you can do just fine with automatic memory: just declare inputText as an array instead of a pointer:
char inputText[size_of_array];
Remember that your size_of_array (or amount_of_bytes_to_allocate) must be large enough to hold the entire string that scanf is going to write into the array, including the terminating null character. Otherwise you'll have undefined behavior again.
First, as a general precaution, it's a good idea to initialize new pointers to NULL so as to ensure they aren't pointing to memory that your program isn't allowed to access.
I would use getline() as an alternative to scanf() especially if the size of your input can vary. It allocates a properly-sized buffer for you, so you don't need to worry about entering too many characters.
char *inputText = NULL;
int inputSize;
if (getline(&inputText, &inputSize, stdin) >= 0)
printf("This is your string: %s\n", inputText);
else
printf("Error\n");
You still need to free the memory allocated to inputText yourself, so don't forget to do that and set it to NULL once you're done with it.

What is the difference of these array declarations? [duplicate]

This question already has answers here:
Difference between char* and char[]
(8 answers)
String Literals
(3 answers)
Closed 9 years ago.
#include <stdio.h>
#include <string.h>
int main(void){
char s1[30]="abcdefghijklmnopqrstuvwxyz";
printf("%s\n",s1);
printf("%s",memset(s1,'b',7));
getch();
return 0;
}
Above code works but when I create s1 array like this,
char *s1="abcdefghijklmnopqrstuvwxyz";
it does not give any errors in compile time but fails to run in runtime.
I am using Visual Studio 2012.
Do you know why?
I found prototype of memset is:
void *memset( void *s, int c, size_t n );
char s1[30] allocates a writable memory segment to store the contents of the array, char *s1="Sisi is an enemy of Egypt."; doesn't - the latter only sets a pointer to the address of a string constant, which the compiler will typically place in a read-only section of the object code.
String literals gets space in "read-only-data" section which gets mapped into the process space as read-only (So you can't change it).
char s1[30]="abcdefghijklmnopqrstuvwxyz";
This declares s1 as array of type char, and initialized it.
char *s1="abcdefghijklmnopqrstuvwxyz";
Will place "abcdefghijklmnopqrstuvwxyz" in the read-only parts of the memory and making a pointer to that.
However modifying s1 through memset yields an undefined behavior.
An very good question!.
If you make gcc output the assembly, and compare the output, you could find out the answer, and the following is why:
char s1[30]="abcdef";
when defined in a function, it will define an array of char, and s1 is the name of the array. The program will allocate memory in stack.
when define globally, it will define a object in the program, and the object is not an read only data.
char* s2 = "abcdef"; only define a point of char, which point to an const char stored in the .rodata, that is the read only data in the program.
To make program run efficiently and make the progress management easily, the compiler will generate different sections for a given code. Constant chars, like the char* s2 = "abcdef"; and the printf format string will be stored in the .section rodata section. After loading into the main memory by the loader of the OS, this section will be marked as read only. That is why when you use memset to modify the memory which s2 point to, it will complain Segment fault.
Here is an explaination: Difference between char* and char[]

C: String manipulation adding more characters without causing a buffer overflow

In C I have a path in one of my strings
/home/frankv/
I now want to add the name of files that are contained in this folder - e.g. file1.txt file123.txt etc.
Having declared my variable either like this
char pathToFile[strlen("/home/frankv/")+1]
or
char *pathToFile = malloc(strlen("/home/frankv/")+1)
My problem is that I cannot simply add more characters because it would cause a buffer overflow. Also, what do I do in case I do not know how long the filenames will be?
I've really gotten used to PHP lazy $string1.$string2 .. What is the easiest way to do this in C?
If you've allocated a buffer with malloc(), you can use realloc() to expand it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char *buf;
const char s1[] = "hello";
const char s2[] = ", world";
buf = malloc(sizeof s1);
strcpy(buf, s1);
buf = realloc(buf, sizeof s1 + sizeof s2 - 1);
strcat(buf, s2);
puts(buf);
return 0;
}
NOTE: I have omitted error checking. You shouldn't. Always check whether malloc() returns a null pointer; if it does, take some corrective action, even if it's just terminating the program. Likewise for realloc(). And if you want to be able to recover from a realloc() failure, store the result in a temporary so you don't clobber your original pointer.
Use std::string, if possible. Else, reallocate another block of memory and use strcpy and strcat.
You have a couple options, but, if you want to do this dynamically using no additional libraries, realloc() is the stdlib function you're looking for:
char *pathToFile = malloc(strlen("/home/frankv/")+1);
char *string_to_add = "filename.txt";
char *p = realloc(pathToFile, strlen(pathToFile) + strlen(string_to_add) + 1);
if (!p) abort();
pathToFile = p;
strcat(p, string_to_add);
Note: you should always assign the result of realloc to a new pointer first, as realloc() returns NULL on failure. If you assign to the original pointer, you are begging for a memory leak.
If you're going to be doing much string manipulation, though, you may want to consider using a string library. Two I've found useful are bstring and ustr.
In case you can use C++, use the std::string. In case you must to use pure C, use what's call doubling - i.e. when out of space in the string - double the memory and copy the string into the new memory. And you'll have to use the second syntax:
char *pathToFile = malloc(strlen("/home/frankv/")+1);
You have chosen the wrong language for manipulating strings!
The easy and conventional way out is to do something like:
#define MAX_PATH 260
char pathToFile[MAX_PATH+1] = "/home/frankv/";
strcat(pathToFile, "wibble/");
Of course, this is error prone - if the resulting string exceeds MAX_PATH characters, anything can happen, and it is this sort of programming which is the route many trojans and worms use to penetrate security (by corrupting memory in a carefully defined way). Hence my deliberate choice of 260 for MAX_PATH, which is what it used to be in Windows - you can still make Windows Explorer do strange things to your files with paths over 260 characters, possibly because of code like this!
strncat may be a small help - you can at least tell it the maximum size of the destination, and it won't copy beyond that.
To do it robustly you need a string library which does variable length strings correctly. But I don't know if there is such a thing for C (C++ is a different matter, of course).

Segmentation fault when using strcpy?

I'm trying to define a path at compile time by passing:
-DDCROOTDEF='"/path/to/stuff"'
on the compile line. I then try to get use this in the code like:
char * ptr_path;
strcpy(ptr_path, DCROOTDEF);
strcat(ptr_path,"/MainCommons/CommonLib/fonts/Arial.ttf");
char *pftf=ptr_path;
gdImageStringFT(pimg,brect,iclr,pftf,pts,ang,ixp,iyp, (char *)cbuf);
Which gives me a segmentation fault. However, if I try to print the string first:
char * ptr_path;
strcpy(ptr_path, DCROOTDEF);
strcat(ptr_path,"/MainCommons/CommonLib/fonts/Arial.ttf");
char *pftf=ptr_path;
printf("%s\n",pftf);
gdImageStringFT(pimg,brect,iclr,pftf,pts,ang,ixp,iyp, (char *)cbuf);
It works just fine. What intricacy of char pointer's am I missing here?
Thanks
char * ptr_path;
strcpy(ptr_path, DCROOTDEF);
You never initialize ptr_path.
It doesn't work in the second code snippet, you are just getting unlucky and it appears to work. You're still using an uninitialized pointer and trying to write to who knows where in memory.
You need to initialize ptr_path to point to an array of char that is at least strlen(DCROOTDEF) + 1 in length. You also need to check the length of DCROOTDEF before copying its contents into the array to be sure that it is not too long. You can do so manually using strlen or you can use a length-checked copy function like strlcpy.
The pointer ptr_path is not initialized to point at writable memory, which is why dereferencing it using strcpy() is crashing.
You need to call e.g. malloc() to get the space, first:
char * ptr_path = malloc(PATH_MAX);
Or something like that.
In
char * ptr_path;
strcpy(ptr_path, DCROOTDEF);
strcat(ptr_path,"/MainCommons/CommonLib/fonts/Arial.ttf");
the pointer is not bound to a legally allocated block of memory, so your program runs into undefined behavior. You need to allocate a buffer first - for example by using malloc(). Be sure that the buffer is large enough to hold the resulting string together with the terminating null character.

Resources