passing pointer to function and accessing it outside - c

I am trying to concatenate two string literal pointers, and store them in a third string which dynamically allocate memory to fit the two string and finally add and print out the string char. I could not print the string outside the function.
//Here is the function
void join(char ptr1, char ptr2, char **ptr3) {
char tempStr[strlen(strPtr1) + strlen(strPtr2)+1];
strcpy(tempStr, ptr1);
strcat(tempStr, ptr2);
*ptr3 = (char*)malloc(strlen(tempStr));
strcpy(ptr3, tempStr);
printf("%s\n", ptr3);
}
in the main I have these variables
char *str1 = "print "; char *str2= "out"; char *str3;
join(str1,str2,&(str3));
printf("%s",str3)://segmentation fault occur here
I have asked similar question about pointer manipulation, and I still struggle with such concepts.

If this is C, you are neglecting to account for the '\0' at the end of the string. Try this
void join(char* ptr1, char* ptr2, char** ptr3)
{
char* result = (char*)malloc(strlen(ptr1) + strlen(ptr2) + 1);
strcpy(result, ptr1);
strcat(result, ptr2);
*ptr3 = result;
}
Also why not just return the new string instead of passing in a reference to ptr3?

The problem in your posted code is that the line
*ptr3 = (char*)malloc(strlen(tempStr));
should be
*ptr3 = (char*)malloc(strlen(tempStr) + 1);
The reason for that is the same as why you needed to use +1 in the line:
char tempStr[strlen(ptr1) + strlen(ptr2)+1];
You can simplify the function by not creating tempStr as a temporary object.
void join(char *ptr1, char *ptr2, char **ptr3) {
*ptr3 = malloc(strlen(ptr1) + strlen(ptr2) + 1);
strcpy(*ptr3, ptr1);
strcat(*ptr3, ptr2);
}

One issue you're having is that you are declaring your ptr1 ad ptr2 as chars instead of pointers.
Any reason you can't use sprintf()?
char join(char *s1, char *s2){
char new_string[80]; // Assuming you know the max size
sprintf(new_string, "%s%s", s1, s2);
puts(new_string);
}

Compiler warnings are not fully enabled. With a good compiler and warnings well enabled, the compiler would have warned. This saves you time and avoids unnecessary posts.
void join(char *ptr1, char *ptr2, char **ptr3) {
...
// warning: passing argument 1 of 'strcpy' from incompatible pointer type
strcpy(ptr3, tempStr);
// Code should have been
strcpy(*ptr3, tempStr);
Some coding ideas: Consider the following that takes advantage of code paying the price to find the string lengths once, no need to do so again.
// As ptr1,ptr2 not changed, use const, it's less restrictive calling
// and potential for additional optimizations.
void join(const char *ptr1, const char *ptr2, char **ptr3) {
size_t len1 = strlen(l1);
size_t size2 = strlen(l2) + 1;
*ptr3 = malloc(len1 + size2);
// Check for allocation success
if (*ptr3)) {
memcpy(*ptr3, ptr1, len1);
memcpy(*ptr3 + len1, ptr2, size2);
printf("%s\n", *ptr3);
}
}

You have two immediate problems here:
You are not allocating space for the null terminator at the end of the resulting string:
*ptr3 = (char*)malloc(strlen(tempStr));
should be
*ptr3 = (char*)malloc(strlen(tempStr) + 1);
You are passing the wrong thing to strcpy.
strcpy(ptr3, tempStr);
should be
strcpy(*ptr3, tempStr);
I suspect the second one is what is directly causing your crash, since it will likely result in the string pointer (str3 in main) getting overwritten with the start of the string, and also overwrite other random stack memory.

Related

Swap strings using strcpy() in a function

i know this is a very simple question but i'm new and a bit down here.. i'm learning more about how to use functions, and i can get this to work if it was simply in main, or i can use another way, but i'm trying to solve it using strcpy(), and i dont want to change the main, everythijg should be in the function, any help is very much appreciated.
char swap_char(char *s1, char *s2) {
printf("before swapping : swap_char(\"%s\", \"%s\")\n", s1, s2);
char temp[50];
strcpy(temp, s1);
strcpy(s1, s2);
strcpy(s2, temp);
printf("After swapping : swap_char(\"%s\", \"%s\")\n", s1, s2);
}
main() {
swap_char("please","work");
}
"please" has 7 characters (including the terminator), but "work" only has 5 characters. There is enough space for the first string to contain "work", but the second string does NOT have enough space to contain "please" in it.
Your code has literal strings "please" and "work", which means they are very likely in READ ONLY memory, and cannot be changed or overwritten.
Fixing these two problems I get:
char swap_char(char *s1, char *s2) {
printf("before swapping : swap_char(\"%s\", \"%s\")\n", s1, s2);
char temp[50];
strcpy(temp, s1);
strcpy(s1, s2);
strcpy(s2, temp);
printf("After swapping : swap_char(\"%s\", \"%s\")\n", s1, s2);
}
int main() {
char alpha[20] = "please"; // Declare space 20: MORE than enough space for either string
char beta[20] = "work"; // Also, use a local array, which is NOT read-only, and can be changed.
swap_char(alpha,beta);
return 0;
}
Output
Success #stdin #stdout 0s 5524KB
before swapping : swap_char("please", "work")
After swapping : swap_char("work", "please")
The first step is reading the docs to see how it can be used and see if they have any helpful examples.
The first issue here is we don't know if we will have enough space to complete this task. Instead we can malloc space dynamically to make sure we don't run into issues.
// We don't need to return a char
void swap_char(char *s1, char *s2) {
printf("before swapping : swap_char(\"%s\", \"%s\")\n", s1, s2);
// Allocate on the heap so we know we will never run out of space on a long input
char temp = malloc(strlen(s1) + 1);
strcpy(temp, s1);
strcpy(s1, s2);
strcpy(s2, temp);
// Free temporary buffer
free(temp);
printf("After swapping : swap_char(\"%s\", \"%s\")\n", s1, s2);
}
However, there is a bigger problem here. We don't know if both pointers have enough memory allocated. This is why this approach is not all that practical. Also by passing the string pointers directly instead of using a pointer to a buffer on the stack or heap risks attempting to mutate read-only memory. String constants are loaded along with the assembly instructions in each function into read-only memory on most modern systems. This is good since it prevents a malicious actor or undefined behavior from modifying the function assembly.
char *a = "please";
char *b = "work";
// Create new buffers with the required space to use instead
unsigned int buffer_len = imax(strlen(a), strlen(b)) + 1;
char *a_buffer = malloc(buffer_len);
char *b_buffer = malloc(buffer_len);
// Copy the input strings into our new buffers
strcpy(a_buffer, a);
strcpy(b_buffer, b);
// Finally swap the buffers
swap_char(a_buffer, b_buffer);
As you can see, it isn't very practical but it is possible. A more practical approach is to just swap the pointers held by variables.
void swap_strings(char **s1, char **s2) {
char *temp = *s1;
*s1 = *s2;
*s2 = temp;
}
char *a = "please";
char *b = "work";
printf("Before swapping : swap_char(\"%s\", \"%s\")\n", a, b);
swap_strings(&a, &b);
printf("After swapping : swap_char(\"%s\", \"%s\")\n", a, b);

Pointers swap values in void function, but won't return swapped values

I'm trying to swap two strings passed in as char pointers.
In debugging, I get the right answers at the end of the called function, but returning the values after the function ends returns the same values as passed in. Here is the code
#include <stdio.h>
int main(int argc, char const *argv[]) {
char *s1, *s2;
s1 = "12345678";
s2 = "87654321";
printf("s1 is %s\n", s1);
printf("s2 is %s\n", s2);
strswap(s1, s2);
printf("s1 is now %s\n", s1);
printf("s2 is now %s\n", s2);
}
and the code for the function itself
#include <stdio.h>
void strswap(char *s1, char *s2){
char *temp;
temp = s1;
printf("temp: %s\n", temp);
s1 = s2;
printf("s1: %s\n", s1);
s2 = temp;
printf("s1: %s\n", s1);
printf("s2: %s\n", s2);
printf("temp: %s\n", temp);
}
I order to swap strings, first of all you can't just use constant string literals since they are immutable. Assigning string literal to char * is considered bad practice unless you properly know what you're trying to achieve. Read this link and this also. You should use statically/dynamically allocated strings.
As other people said, you're passing the character pointers by value, so any changes you make in strswap() would not be reflected in main function. Since some local variables are modified and they get destroyed when control goes out of those functions. You should either pass char ** like in one of the mentioned answers. I would recommend to use statically allocated strings and use strcpy for string copy operations like this:
#include <stdio.h>
#include <string.h>
#define MAX_SIZE 1000
void strswap(char *s1, char *s2){
char tempStr[MAX_SIZE];
strcpy(tempStr, s1);
strcpy(s1, s2);
strcpy(s2, tempStr);
}
int main(int argc, char const *argv[]) {
char aString1[MAX_SIZE] = "Rohan", aString2[MAX_SIZE] = "Rohit";
printf("s1 is %s\n", aString1);
printf("s2 is %s\n", aString2);
strswap(aString1, aString2);
printf("s1 is now %s\n", aString1);
printf("s2 is now %s\n", aString2);
return 0;
}
C uses pass-by-value for function argument passing.
Here, the pointers themselves are passed by value, so any changes made to the pointers (for example, assigning values to them), will not be reflected to the actual arguments in the caller. However, if any change is made to the value stored at the memory location pointed to by the pointers, that would be reflected to the actual arguments used to call the function from the caller.
So, to change a pointer value itself, you need to pass a pointer to the pointer.
You're using string literals to initialize the pointers, you can't swap those strings with the function prototype you showed.
Assuming the string initialization is a mistake, we can do the swap without changing the function's prototype, by copying the actual characters around. This requires that the strings have equal length, otherwise the longer one can't be copied to the space used by the shorter one.
Here's an attempt:
void swap_strings(char *a, char *b)
{
const size_t al = strlen(a);
const size_t bl = strlen(b);
if(al != bl)
return;
for(size_t i = 0; i < al; ++i)
{
const char t = a[i];
a[i] = b[i];
b[i] = t;
}
}
I changed the function's name, I have a vague recollection that you're not supposed to add functions with names beginning with str, that's reserved.
Note: this requires that the strings be writable, so you can't use it on string literals. You have to have proper buffers (or arrays) like this:
char a[] = "foo";
char b[] = "bar";
swap_strings(a, b);
printf("'%s' and '%s'\n", a, b);
This will print 'bar' and 'foo'.

strcpy with destination pointer and return value

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.

Append char to string with no value

How would I append a char to string that has no initial value in the following method I've started:
void append(char a) {
const char *str;
char *ret = malloc (strlen(str)+2);
strncpy(str,strlen(str),ret);
ret[strlen(str)-2] = a;
ret[strlen(str)-1] = 0;
printf("%s", str);
}
I've tried a few different answers to other questions but none have worked, please help.
Since the pointer str is not initialized, you can't add characters to what it points at. What makes sense depends on what you're going to do next. Since you don't return a value from the function, you can't access the string to which a is appended unless append calls some other function.
char *str; is not a string. It is a mnemonic that says that *str will give you a value which is supposedly a character.
str is a pointer that points at random. Make it point to an allocated bunch of memory first.
Do something like- str = malloc(100); and then do a *(str+1) = a and then a *(str+2) = '\0' to NULL terminate the string.
how about something like:
char * append(char a, const char * str)
{
char *ret = malloc (strlen(str)+2);
strncpy(str,strlen(str),ret);
ret[strlen(str)-2] = a;
ret[strlen(str)-1] = 0;
return ret;
}

Did this program initialize its pointer?

This is a simple program to copy a string to a new string from a C programming book (Programming in C, S. Kochan). It runs fine, but there is a pointer that I do not see initialized. I'm struggling with pointers here, but I have imbedded in my coding the C golden commandment: "THOU SHALT NOT USE THY POINTERS THAT ARE NOT INITIALIZED". Here is the code:
#include <stdio.h>
void copyString(char *to, char *from) //I do not see where the 'from' pointer is initilized?
{
for( ; *from != '\0'; ++from, ++to)
{
*to = *from;
}
*to = '\0';
}
int main(void)
{
void copyString (char *to, char *from);
char string1[] = "A string to be copied.";
char string2[50];
copyString(string2, string1);
printf("%s\n", string2);
copyString(string2, "So is this.");
printf("%s\n", string2);
return 0;
}
I was under the impression that all pointers must be initialized in the manner:
*ptr = &variable;
or risk something important in your system being overridden. But I am seeing many programs in my books that are not initializing pointers explicitly, and this makes me very uncomfortable. Please give me some tips about prudent pointer use so I don't destroy my machine, especially anything pertaining to strings. Thanks in advance all!
This confuses you - void copyString (char *to, char *from);. This is just a declaration in main. char *to and char *from in main are not in use so do not worry. The above code is as good as:
#include <stdio.h>
void copyString(char *to, char *from) //I do not see where the 'from' pointer is initilized?
{
for( ; *from != '\0'; ++from, ++to)
{
*to = *from;
}
*to = '\0';
}
int main(void)
{
void copyString (char *, char *);
char string1[] = "A string to be copied.";
char string2[50];
copyString(string2, string1);
printf("%s\n", string2);
copyString(string2, "So is this.");
printf("%s\n", string2);
return 0;
}
//I do not see where the 'from' pointer is initilized?
When you pass arguments like this copyString(string2, string1); - They will be copied into the args on function call of copyString(char *to, char *from). So in the first call:
copyString(string2, string1); - to = string2, and, from = string1
"A string to be copied."
from--^
And in the second call:
to = string2, and, from = "So is this."
"So is this."
from--^
string2 does not cause any problems (even though it was not initialized) since your overwriting its values (which had garbage values before).
to and from are function parameters, when the function is called, they are assigned the value of the arguments:
copyString(string2, string1);
to is assigned the value of stirng2 while from is assigned the value of string1. Note that even though string2 and string1 has type of char arrays, but they "decayed" into a pointer to the first element when passed as function arguments.
You are correct - all pointer must be initialized as you said.
When you're declaring the strings, as an array of characters as below:
char string1[] = "A string to be copied.";
char string2[50];
string1 and string2 are pointer to arrays of strings. So, they are already pointers.
When you used them in the copyString function, you are already using pointers, and the assignent is done implicitly. So:
to = string2 = &string2[0];
Here is a commented version of your code - the "from" variable has been renamed to source, and the printf's for the pointer values should illustrate the source. But suffice to say that the arguments to the copyString function are provided by the two calls to the function in your main program. The compiler generates code which takes the arguments you provide in the calls to the function with instructions to save these arguments onto the function call stack frame. Then when the function is called, these values are referenced in the function.
#include <stdio.h>
//the char pointer dest is provided as an argument
//the char pointer source is provided as an argument
char*
copyString(char *dest, char *source)
{
if(!dest) return dest;
if(!source) return dest;
printf("dest %x, source %x\n", dest, source);
//for each character in source, until *source == '\0'
for( ; *source; )
{
//assign the char at *dest into *source
//then post-increment source, dest
*dest++ = *source++;
}
//ensure the dest string is terminated
*dest = '\0';
return dest;
}
int main(void)
{
char* copyString (char *to, char *source);
char string1[] = "A string to be copied.";
char string2[50];
printf("string2 %x, string1 %x\n", string2, string1);
copyString(string2, string1);
printf("%s\n", string2);
copyString(string2, "So is this.");
printf("%s\n", string2);
return 0;
}
When you run the program, you will see the locations of the source and destination pointers provided,
$ ./copystr
string2 bff0dbe7, string1 bff0dc19
dest bff0dbe7, source bff0dc19
A string to be copied.
dest bff0dbe7, source 80485f0
So is this.

Resources