My plain C is a bit rusty, and I currently try to figure out why the first works and the second doesn't.
char *returnSomething(void) {
char *s = (char *) malloc(5 + 1);
strcpy(s, "Hello");
return s;
}
void dontReturnSomething(char *dest) {
char *s = (char *) malloc (5 + 1);
strcpy(s, "Hello");
dest = malloc(strlen(s) + 1);
strcpy(dest, s);
free(s);
}
int main(int argc, char *argv[]) {
char *first = returnSomething();
char *second = NULL;
dontReturnSomething(second);
printf("first: %s | second: %s", first, second);
}
Isn't it basically doing the same thing?
To return a pointer through a parameter you need a pointer to a pointer. Declare dest as char **dest.
void dontReturnSomething(char **dest) {
char *str = "Hello";
*dest = malloc(strlen(str) + 1);
strcpy(*dest, str);
}
Call the function like this:
dontReturnSomething(&second); // pass in address of second
To be more accurate, pointers to pointers are only necessary so long as, just as in the examples above, the memory is not allocated until after you enter the function. Just wanted to say this for anyone having pointer problems and thinks any passing of pointers always requires pointers to pointers to be passed.
For example, the below example works just fine.
void dontReturnSomething(int* testint)
{
int test = 33;
*testint = test;
}
int main(int argc, char *argv[])
{
int *first = calloc(1,sizeof(int));
printf("Before: %d\n", *first);
dontReturnSomething(first);
printf("After: %d\n", *first);
return(1);
}
If you run it, you'll get 0 and 33 as expected. Of course the caveat to this is that you absolutely have to have memory allocated to the pointer being used. If you allocated memory for the pointer inside the function, then you will be assigning it a new address that would then have to be returned so that the address can persist. The below example also works just fine.
void dontReturnSomething(char* testchar)
{
char* test = "Hello World!";
strcpy(testchar,test);
}
int main(int argc, char *argv[])
{
char *hello = NULL;
hello = calloc(13, sizeof(char));
printf("Before: %s\n", hello);
dontReturnSomething(hello);
printf("After: %s\n", hello);
return(1);
}
Of course you will pretty much never know the size of a string, or more usually a buffer, ahead of time. I just think it's important to understand the subtleties of pointers.
Related
I have to make a function that accepts two string pointers as arguments - one having content, and one being empty, and that copies the content of the first one onto the second one.
How would I go about doing this? Here is the code I have, but it just crashes when run:
#include <stdio.h>
void strcopy1(char* mainStr[], char* emptyStr[], int size)
{
for(int i = 0; i < size; i++)
{
*emptyStr[i] = *mainStr[i]; //The issue is on this line. How do I do this?
}
}
int main(void)
{
char *s1 = "Barrel";
char *e1;
printf("mainStr is: %s\n", s1);
printf("emptyStr is: %s\n", e1);
strcopy1(&s1, &e1, 7);
printf("mainStr is: %s\n", s1);
printf("emptyStr is: %s\n", e1);
}
Thanks in advance.
Several problems:
You didn't allocate space for the destination string.
You don't need to pass pointers to the variables, just pass the pointer variables themselves.
You can't print the empty string before calling the function, since you haven't initialized any of its contents.
The elements of the arrays are char, not pointer to char, so you don't need to use *mainStr[i] or *emptyStr[i].
Code:
#include <stdio.h>
void strcopy1(char mainStr[], char emptyStr[], int size)
{
for(int i = 0; i < size; i++)
{
emptyStr[i] = mainStr[i];
}
}
int main(void)
{
char *s1 = "Barrel";
size_t len = strlen(s1) + 1; // Add 1 for the trailing null byte
char *e1 = malloc(len);
printf("mainStr is: %s\n", s1);
strcopy1(s1, e1, len);
printf("mainStr is: %s\n", s1);
printf("emptyStr is: %s\n", e1);
free(e1); // Always free dynamically-allocated memory
}
I think the problem lies in the line where you are calling the function. I found a solution for you that works fine.
copy_string(char *target, char *source)
{
while(*source)
{
*target = *source;
source++;
target++;
}
*target = '\0';
}
This function will do the trick for you.
First you're trying to display a non initialized String which is impossible.
Second, I don't understand why the parameters are an array of pointers.
Here's what I propose :
void strcopy1(char *mainStr, char *emptyStr) {
while (*mainStr) {
*emptyStr = *mainStr;
mainStr++;
emptyStr++;
}
*emptyStr = '\0';
}
int main(void)
{
char *s1 = "Barrel";
char *e1;
printf("mainStr is: %s\n", s1);
strcopy1(&s1, &e1);
printf("mainStr is: %s\n", s1);
printf("emptyStr is: %s\n", e1);
}
The following is your code with corrections annotated in-line:
// pointer to pointer is not needed, change argument to char *
//void strcopy1(char* mainStr[], char* emptyStr[], int size)
void strcopy1(char* mainStr, char* emptyStr, int size)
{
for(int i = 0; i < size; i++)
{
//*emptyStr[i] = *mainStr[i]; //The issue is on this line. How do I do this?
emptyStr[i] = mainStr[i]; //reference variable, not pointer to variable
}
}
int main(void)
{
char *s1 = "Barrel";
char *e1 = {0}; // initialize variable
e1 = malloc(strlen(s1)+1); //allocate memory to target string (+1 for NULL)
if(e1)//ensure e1 memory was created
{
printf("mainStr is: %s\n", s1);
printf("emptyStr is: %s\n", e1);
strcopy1(s1, e1, 7); //string variables are already pointers
//no need for the "address of" operator
printf("mainStr is: %s\n", s1);
printf("emptyStr is: %s\n", e1);
free(e1); //always free memory when explicitly created using malloc()
}
return 0;//add return to match your 'main' prototype
}
In answer to your question in comments:
After changing the e1 line to be "char *e1[7];" or "char e1 = " "; and removing the ampersands, it still crashes.
1) Changing char *e1 to char *e1[7] is creating char *[7], but you need either a char * or a char [7] for the job. Either will create containers adequate for use as a C string passed as an argument. (however char * needs memory allocated ([m][c]alloc) before use)
2) Regarding removing ampersands, this was explained above as well, but basically, the & is the address of operator, since C string names (variables) are already pointing to the address of the string, the & operator is not needed.
Ii've a big Problem. I write a static Library, what I would like to use in a Software. My Problem is: if you give a pointer from a function out of the library back to the main program the pointer have not the value from the pointer in the Library. Is there an issue, if you give pointer from an Libay.a back to the main.c
Main.c:
#include <stdio.h>
int main(int argc, const char * argv[]) {
char *ptr;
Prallow_its(ptr, 122);
printf("%s", ptr);
return 0;
}
Prallow.c from Prallow.a
[...]
char *Prallow_its(char *ptr, int i){
static char buffer[255];
sprintf(buffer, "%u", i);
ptr = buffer;
return ptr;
}
[...]
It's fine to return the pointer to your static buffer from the library. It lives in the same address space as the rest of your program. Of course, it's not thread-safe but that's a separate issue.
The real problem is the way you are calling it:
char *ptr; // <-- ptr uninitialised
Prallow_its(ptr, 122); // <-- return value ignored
printf("%c", ptr); // <-- ptr still uninitialised
You should instead do this:
ptr = Prallow_its( ptr, 122 );
Alternatively, you could allow ptr to be modified by Prallow_its. In that case, it must be defined like this:
char *Prallow_its( char **ptr, int i )
{
static char buffer[255];
sprintf(buffer, "%u", i);
*ptr = buffer;
return *ptr;
}
And called like this:
Prallow_its( &ptr, 122 );
C passes by value, so the line ptr = buffer in the library function does not change the value of ptr in main.
Also, the library function doesn't do anything with the pointer that's passed in, so there's no reason to pass the pointer. The code in Main.c should be
int main(int argc, const char * argv[])
{
char *ptr = Prallow_its(122);
printf("%s", ptr);
return 0;
}
and the code in Prallow.c should be
char *Prallow_its(int i)
{
static char buffer[255];
sprintf(buffer, "%u", i);
return buffer;
}
I am trying to implement
void strcpyy(char *s, char *t){
while(*s++ = *t++){
}
}
which is an example from K&R. The implementation should be fairly easy but for some reason, that is not the case for me at the moment. So I have the following
int main(){
char *mess = "hello world";
char *mess = (char *) malloc(strlen(mess) + 1);
char *aess;
strcpyy(aess, mess);
printf("%s", aess);
return 0;
}
Every time I run the program, I keep on getting a big list of errors each time I run with -Wall. I would think that to implement and use strcpyy, you would have to malloc space to copy the string and once you do so, you should be able to print out aess which theoratically should contain a copy of mess. Any help would be much appreciated!
It is always a good practice to pay attention to the error messages, especially to the first message (others often are the consequences of the first error). The error message surely indicated the line number corresponding to the line with malloc, and most probably told you what's the problem there.
Correct your program to read:
char *mess = "hello world";
char *aess = (char *) malloc(strlen(mess) + 1);
or the complete function is:
int main(){
char *mess = "hello world";
char *aess = (char *) malloc(strlen(mess) + 1);
strcpyy(aess, mess);
printf("%s", aess);
return 0;
}
The problem is that your line
char *mess = (char *) malloc(strlen(mess) + 1);
overwrites the first line
char *mess = "hello world";
and the line
char *aess;
leaves the variable unassigned.
The compile error is because the compiler cannot choose between
char *mess = "hello world";
and
char *mess = (char *) malloc(strlen(mess) + 1);
which introduce a new variable each but with the same name.
The program will look the following way
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void strcpyy( char *s, const char *t )
{
while ( *s++ = *t++ );
}
int main( void )
{
char *t = "hello world";
char *s = ( char * )malloc( strlen( t ) + 1 );
strcpyy( s, t );
printf( "%s\n", s );
free( s );
return 0;
}
change
char *mess = "hello world";
char *mess = (char *) malloc(strlen(mess) + 1);
char *aess;
to
char *mess = "hello world";
char *aess = malloc(strlen(mess) + 1);
mess is a string literal, which is hold in read-only memory. you were overwriting it and losing string that you wanted to copy. you need to assign some space for place where you want to copy characters, in your case aess variable. also, remember to free(aess); at the end of your program. if not, you'll get memory leaks.
why are you declaring and defining mess two times? never declare two variables with the same name if they have the same scope ,by doing this you confuse the compiler;
I'd recommed using strdup like this :
int main(){
char *mess = strdup("hello world");
char *aess;
strcpyy(aess, mess);
printf("%s", aess);
return 0;
}
or just a plain array like this
int main(){
char mess[] = "hello world";
char *aess;
strcpyy(aess, mess);
printf("%s", aess);
return 0;
}
I'm creating a program where a struct is created through this process:
TokenizerT *TKCreate(char *separators, char *ts) {
TokenizerT * inu = malloc(sizeof(*inu));
char * sts = malloc(strlen(ts)*sizeof(char));
char * by = malloc(lim*sizeof(char));
strcpy(by, yr);
strcpy(sts, ts);
inu->sep = by;
inu->toks = sts;
return inu;
}
I need to free the struct inu through another function, but my function below only seems to free up the memory associated with TokenizerT.sep
void TKDestroy(TokenizerT *tk) {
free(tk->sep);
free(tk->toks);
}
How do I free up tk.sep and tk.toks?
EDIT: free(tk) results in this error: "malloc: * error for object 0x7fff55662bd8: pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug"
EDIT2: Struct definition
struct TokenizerT_ {
char * sep;
char * toks;
};
And
void TKDestroy(TokenizerT *tk) {
free(tk->sep);
free(tk->toks);
free(tk);
}
results in the same error specified in EDIT 1
EDIT 3: I've also added my main method:
int main(int argc, char **argv) {
char * arr = argv[1];
char * y = argv[2];
TokenizerT jer = *TKCreate(arr, y);
TKDestroy(&jer);
return 0;
}
First of all, the malloc of "inu" seems not correct
TokenizerT * inu = malloc(sizeof(inu));
I believe it only get memory with 4 bytes (in 32-bit system)
It should be:
TokenizerT * inu = malloc(sizeof(TokenizerT ));
And as you mentioned -- "I need to free the struct inu"
I think the allocated "inu" is passed into "TKDestroy(TokenizerT *tk)"
then:
void TKDestroy(TokenizerT *tk) {
free(tk->sep);
free(tk->toks);
free(tk) // this free is what you want to free "inu"
You just need to reverse the operations you did for allocation:
void TKDestroy(TokenizerT *tk) {
free(tk->sep); // for the 3rd malloc()
free(tk->toks); // for the 2nd malloc()
free(tk); // for the 1st malloc()
}
BTW: you know that sizeof(char) is always 1 - per definition?
The error you get results from your wrong allocation of tk - you just allocated enough memory for a pointer, not for the whole struct. That will mess things up.
Concerning your main, replace:
TokenizerT jer = *TKCreate(arr, y);
TKDestroy(&jer);
With:
TokenizerT *jer = TKCreate(arr, y);
TKDestroy(jer);
The reason being that your create-function returns a pointer, which you then pass to your destroy-function...
The reason that your code fails with that error is that &jer is the address of a local variable. It is the not address returned by the call to malloc.
TokenizerT jer = *TKCreate(arr, y);
TKDestroy(&jer);
So, jer is a local variable. The address returned by TKCreate is immediately de-referenced, and a copy of the struct is made. You simply fail to retain the address returned by TKCreate and it is leaked. Then when you attempt to call free on &jer, the address of a local variable, your environment correctly reports that you are passing to free an address that was not created by a call to malloc.
As I said in your previous question, it makes a lot more sense to return the struct by value than using dynamic allocation. On top of that, your string allocations are incorrectly performed. You must always allocate sufficient room for the null-terminator.
I would write your program like this:
#include <stdlib.h>
#include <string.h>
typedef struct {
char *sep;
char *toks;
} TokenizerT;
TokenizerT TKCreate(const char *seps, const char *toks)
{
TokenizerT inu;
inu.sep = malloc(strlen(seps)+1);
strcpy(inu.sep, seps);
inu.toks = malloc(strlen(toks)+1);
strcpy(inu.toks, toks);
return inu;
}
void TKDestroy(TokenizerT *tk)
{
free(tk->sep);
free(tk->toks);
}
int main(int argc, char **argv)
{
TokenizerT jer = TKCreate(argv[1], argv[2]);
TKDestroy(&jer);
return 0;
}
Notes:
By definition, sizeof(char) is 1 so idiom dictates that it is omitted as a multiplicative factor in calls to malloc().
I've given the parameters to TKCreate the same names as the fields of the struct. This makes it easier to understand what is going on. What's more, your code looked plain wrong since it was ignoring one of the parameters.
As stated above, the struct is returned by value. This is conceptually easier to handle.
You might prefer to write a helper function to duplicate strings. If your compiler's runtime already has a function named strdup you might use that. Otherwise you can use this trivial implementation:
char *strdup(const char *str)
{
char *result = malloc(strlen(str)+1);
strcpy(result, str);
return result;
}
If you only want to search for the null-terminator once you write it like this:
char *strdup(const char *str)
{
size_t len = strlen(str)+1;
char *result = malloc(len);
memcpy(result, str, len);
return result;
}
Then the code becomes:
#include <stdlib.h>
#include <string.h>
char *strdup(const char *str)
{
size_t len = strlen(str)+1;
char *result = malloc(len);
memcpy(result, str, len);
return result;
}
typedef struct {
char *sep;
char *toks;
} TokenizerT;
TokenizerT TKCreate(const char *seps, const char *toks)
{
TokenizerT inu;
inu.sep = strdup(seps);
inu.toks = strdup(toks);
return inu;
}
void TKDestroy(TokenizerT *tk)
{
free(tk->sep);
free(tk->toks);
}
int main(int argc, char **argv)
{
TokenizerT jer = TKCreate(argv[1], argv[2]);
TKDestroy(&jer);
return 0;
}
If you are desperate to return a pointer to the struct, do it like this:
#include <stdlib.h>
#include <string.h>
char *strdup(const char *str)
{
size_t len = strlen(str)+1;
char *result = malloc(len);
memcpy(result, str, len);
return result;
}
typedef struct {
char *sep;
char *toks;
} TokenizerT;
TokenizerT *TKCreate(const char *seps, const char *toks)
{
TokenizerT *inu = malloc(sizeof *inu);
inu->sep = strdup(seps);
inu->toks = strdup(toks);
return inu;
}
void TKDestroy(TokenizerT *tk)
{
free(tk->sep);
free(tk->toks);
free(tk);
}
int main(int argc, char **argv)
{
TokenizerT *jer = TKCreate(argv[1], argv[2]);
TKDestroy(jer);
return 0;
}
Note particularly the difference in the way I call TKCreate and TKDestroy.
Finally, I have ignored all error checking on the calls to malloc(). In real production code you would not do that, but for the sake of clarity of exposition it is much better to omit it here.
In C, I am trying to set a pointer's value by sending it to a function, but the value wont change outside of the function. Here is my code:
#include <stdio.h>
void foo(char* str) {
char* new_str = malloc(100);
memset(new_str, 0, 100);
strcpy(new_str, (char*)"new test");
str = new_str;
}
int main (int argc, char *argv[]) {
char* str = malloc(100);
memset(str, 0, 100);
strcpy(str, (char*)"test");
foo(str);
printf("str = %s\n", str);
}
I want to print out:
str = new test
but this code prints out:
str = test
Any help will be appreciated. Thanks in advance.
There is no pass-by-reference in C. If you provide str as the argument to a function in C, you are always passing the current value of str, never str itself.
You could pass a pointer to str into the function:
void foo(char** pstr) {
// ...
*pstr = new_str;
}
int main() {
// ...
foo(&str);
}
As Eiko says, your example code leaks the first memory allocation. You're no longer using it, and you no longer have a pointer to it, so you can't free it. This is bad.
You need to use pointer to the pointer, untested:
#include <stdio.h>
void foo(char** str)
{
char* new_str = malloc(100);
memset(new_str, 0, 100);
strcpy(new_str, (char*)"new test");
if (str) { /* if pointer to pointer is valid then */
if (*str) /* if there is a previous string, free it */
free(*str);
*str = new_str; /* return the string */
}
}
int main (int argc, char *argv[])
{
char* str = malloc(100);
memset(str, 0, 100);
strcpy(str, (char*)"test");
foo(&str);
printf("str = %s\n", str);
}
You are just reassigning a pointer, which is a local variable in foo.
If you want to copy the string, use strcpy(str, new_str);
You could pass a reference to the pointer instead and reassign, but this can easily lead to memory leaks and is hard to maintain.
Edit: For the pseudo pass by reference see the answer by Steve.
I did it this way by returning the pointer from the function. There is no reason to use malloc in this case, so you don't have to worry about freeing.
gcc 4.4.3 c89
char* print_test(char *str)
{
char *new_str = "new_test";
printf("new_str [ %s ]\n", new_str);
str = new_str;
return str;
}
int main(void)
{
char *str = "test";
printf("str [ %s ]\n", str);
str = print_test(str);
printf("str [ %s ]\n", str);
return 0;
}