How can I assign a string to a char* pointer? - c

I am a newbie to C and it took me 2 hours to figure out the problem.
void helper(char* a, char* b){
a = malloc(strlen(b));
memcpy(a, b, strlen(b));
printf("%s %s\n", a, b);
}
int main(){
char* b = "hello";
char* a;
helper(a, b);
printf("%s", a);
}
While a is always null. Is there anything I missed?

In main(), a and b are pointers.
helper(a, b); gives a copy of pointer a and a copy of pointer b to helper() as part of the call to helper().
The function completes.
The a in main() is not updated/changed by the call helper(a, b). Neither is b changed.
Code needs a new approach of which there are several good ones. Example: Use the return value of helper2().
char *helper2(const char *source);
int main(void) {
const char* b = "hello";
char* a = helper2(b);
printf("<%s>", a);
free(a);
}
Now create helper2(). Code template follows:
#include <...> // whats includes are needed.
#include <...>
char *helper2(const char *source) {
size_t size_needed = ....; // length + 1 for the null character
char *destination = ...' // allocate
if (destination ...) { // Successful allocation?
memcpy(destination, ...., ...); // copy - include null character
}
return ... // What should be returned here?
}

You've missed the fact that main() passes a copy of a to helper() by value. So the a in helper() is a completely different variable (even though you've given it the same name) - it has a different address.
The change of a in helper() therefore does not affect the a in main() at all.
Regardless of what helper() does, main() exhibits undefined behaviour. a is uninitialised, so passing its value to helper() gives undefined behaviour. Passing it to printf() gives undefined behaviour for the same reason.
The printf() call in helper() also has undefined behaviour, since %s causes printf() to expect a string terminated by a '\0', but the memcpy() call has not copied such a thing to a. Practically, printf() will probably keep stepping from a through random memory until it happens to find a byte with zero value. This may result in garbage output or (if there is no such byte in memory) an obscure program crash.
A partial fix of your code would be to make the change of a in helper() visible to main(). For example;
/* Danger: This code still has undefined behaviour */
void helper(char **a, char* b)
/* note usage of extra * on every usage of a in this function */
{
*a = malloc(strlen(b));
memcpy(*a, b, strlen(b));
printf("%s %s\n", *a, b);
}
int main()
{
char* b = "hello";
char* a;
helper(&a, b); /* note use of ampersand here */
printf("%s", a);
free(a); /* a has been malloc()ed, so free() it */
/* using a here will give undefined behaviour, since it is free()d */
}
This code makes the changes to a in helper() visible to main(), by use of pointers.
The problem with this partially fixed code code is that %s still causes printf to expect that a to be terminated with a trailing '\0', but the memcpy() does not copy such a trailing '\0'. So both printf() calls (in both helper() and main()) still have undefined behaviour.
To fix this, we need to change helper() to
void helper(char **a, char* b)
{
*a = malloc(strlen(b) + 1);
memcpy(*a, b, strlen(b) + 1);
printf("%s %s\n", *a, b);
}
which allocates a larger buffer, and copies the content of b - with its contained '\0' into that additional length.
An alternative is to use strcpy() instead of memcpy().
void helper(char **a, char* b)
{
*a = malloc(strlen(b) + 1);
strcpy(*a, b);
printf("%s %s\n", *a, b);
}
The only difference is that strcpy() copies characters until it finds the trailing '\0' in b.

You didnt change a inside the function. when you did malloc a received new address.
void helper(char **a, char *b){
*a = malloc(strlen(b)+1); //+1 for the \0 in the end of b
strcpy(*a, b);
printf("%s %s\n", *a, b);
}
int main(void){
char *b = "hello";
char *a;
helper(&a, b);
printf("%s\n", a);
}
And in you code you didnt use free.. You have to free all the pointers that you did malloc...
so add free(a) in the end of the main.

I renamed variables, to be clear. What #chux said, is value of variable 'a' changed, but value of variable 'x' - not.
void helper(char* a, char* b){
a = malloc(strlen(b));
memcpy(a, b, strlen(b));
printf("%s %s\n", a, b);
}
int main(){
char* y = "hello";
char* x;
helper(x, y);
printf("%s", x);
}
UPD: This is an original code. I just renamed variables in order to disambiguate variables naming, and to do explanations more clear. The problem, as it was pointed by #chux, variable x sent by value, and so cannot be changed in function main.

First mistake I saw is that you have ever to allocate strlen(foo)+1. the correct size for copy a string is this. Than call strcpy() or memset +1 . But with strings I ever use strcpy() on my mind is more performant:
char *strcpy(char *a , const char*b)
{
while(*a++=*b++)
;
return a;
}
then (this is a very trivial version, the real one has more checks)
char * memcpy(a,b,n)
{
while(n--)
*a++=*b++;
return a;
}
there is a counter more to decrease; With memset you have also to call strlen() for get the length, and add one. With strcpy() is not required. So yes, the differences are not appreciable, but there are, but what is appreciable is the redeability, the clearness of the code all this with (teorethical, unless some compiler optimization) better performance

Related

converting a string to a void pointer

I'm trying to figure out how to "transform" strings (char*) to void* and viceversa.
When I execute this my output is just the first printf and ignores the second one, it doesn't even write "after = "
PS This little program is just to understand, I know i could actually use swap(&s[0],&s[1]). I need to know how to properly cast a void pointer into an array of strings.
I'm working on a uni project where I need to create my own quick_sort algorythm and I need the swap function inside of it to work with void pointers.
#include <stdio.h>
#include <stdlib.h>
static void swap(char** x,char** y);
static void swap(char** x,char** y){
char* temp=*x;
*x=*y;
*y=temp;
}
int main()
{
char* s[2];
s[0]="weee";
s[1]="yooo";
void* array=s;
printf("before %s %s\n",s[0],s[1]);
swap((&array)[0],(&array)[1]);
printf("after = %s %s",(char*)array,(char*)array);
return 0;
}
I think I'm missing something big
Thanks in advance :D
In this declaration the array s used as an initializer is implicitly converted to a pointer to its first element of the type char **.
void* array = s;
In the call of the function swap
swap((&array)[0],(&array)[1]);
the first argument can be the pointer array itself that will be implicitly casted to the pointer type of the corresponding parameter
swap( array, (&array)[1]);
But you need to correctly pass the second argument. To do this you need to cast the pointer array explicitly like
swap( array, ( char ** )array + 1 );
In the call of printf you need also correctly to supply argument expressions.
Here is your updated program
#include <stdio.h>
static void swap(char** x,char** y);
static void swap(char** x,char** y){
char* temp=*x;
*x=*y;
*y=temp;
}
int main()
{
char* s[2];
s[0]="weee";
s[1]="yooo";
void* array=s;
printf("before %s %s\n",s[0],s[1]);
swap( array, ( char ** )array + 1 );
printf("after = %s %s", *(char**)array, ( (char**)array )[1]);
return 0;
}
The program output is
before weee yooo
after = yooo weee
void *array = s; declares array to be a void *. Then &array is the address of that void *, so &array[1] would access a void * after it. But there is no void * after it, since void *array defines a single void *.
array could be properly defined to alias s with char **array = s;, after which swap(&array[0], &array[1]); would work as desired.
If you define array as void **array = (void **) s;, then swap(&array[0], &array[1]); will produce diagnostic messages because the types are wrong. You could use swap((char **) &array[0], (char **) &array[1]);.
Then, if you print the strings with printf("after = %s %s", array[0], array[1]);, this will work, although it is not entirely proper code. Using array[0] as an argument passes a void * where printf is expecting a char * for the %s. However, the C standard guarantees that void * and char * have the same representation (encode their values using bytes in memory in the same way), and it further says (in a non-normative note) that this is intended to imply interchangeability as arguments to functions.
The void* doesn't seem to fulfil any particular purpose here, just swap the pointers: swap(&s[0],&s[1]);.
You could also do this:
char** ptr = &s[0];
printf("before %s %s\n",ptr[0],ptr[1]);
swap(&ptr[0],&ptr[1]);
printf("after = %s %s",ptr[0],ptr[1]);
If you for reasons unknown insist on using void* then note that as your code stands, it points at the first char* in your array of char*. However, it isn't possible to perform pointer arithmetic on void* since that would entail knowing how large a "void" is. The void* doesn't know that it points at an array of pointers. Therefore array[i] is nonsense.
Also, the void* are set to point at char* so you simply cannot pass it to a function expecting a char**. You'd have to rewrite the whole program in a needlessly obfuscated way, so just abandon that idea.

How to change a pointer value between functions

I am new to C, and am confused on how to change the value of a char * between functions.
For example:
#include <stdio.h>
void testing(char *s) {
s = "hi";
} // testing
int main() {
char *s = "hello";
testing(s);
printf("%s\n", s);
} // main
In this case, the value of s is not changed, and "hello" is printed.
How can I change s, without having to change the return type or parameters of either function?
C function calls are strictly pass-by-value. This means that when you pass s to testing, a local copy is made. Assigning a new value to s in the function will therefore not affect the value in main.
Since the value of the pointer is copied, however, you can access the memory it points to. If s points to memory that isn't read-only, you could copy the contents of one buffer to another. For example, instead of s = "hi";,
strcpy(s, "hi");
In main, the statement char *s = "hello"; is likely to have s point to a read-only buffer. To make it a writable buffer, declare s as an array instead:
char s[] = "hello";
If you want to change the value of the pointer, rather than what it points to, you need to pass in the address of the memory containing main's version of s: a pointer to a pointer. That would look like this:
#include <stdio.h>
void testing(char **s) {
*s = "hi";
} // testing
int main() {
char *s = "hello";
testing(&s);
printf("%s\n", s);
} // main
Another (perhaps better in this context) way is to use return values instead of parameters for both input and output:
#include <stdio.h>
char *testing(char *s) {
s = "hi";
return s;
} // testing
int main() {
char *s = "hello";
s = testing(s);
printf("%s\n", s);
} // main
In main, char *s is initialized to the string literal "hello". This means s will be pointing to an anonymous array of 6 char containing the values { 'h', 'e', 'l', 'l', o', '\0' }. However, the contents of this array are not modifiable as far as the standard is concerned, so any code that writes to this array exhibits undefined behavior.
In the call to testing, the parameter char *s is treated as a local variable within the function. Any change to the pointer value will not affect the char *s variable in main. In C function calls, all parameters are passed by value.
Within testing, you change s to point to another string literal "hi". Similar to the initialization in main, testing's s will now point to an anonymous array of 3 char containing the values { 'h', 'i', '\0' }. The contents of this anonymous array are not modifiable. As mentioned above, this has no effect on main's s pointer.
You stated that you do not wish to modify the parameters or return type of either function. In order to do that, testing will need to overwrite the contents of the array pointed to by its parameter s. Since the current code in main has s pointing to a non-modifiable array, you will need to change it to point to a modifiable array. This can be done by changing main's s into an array instead of a pointer:
int main() {
char s[] = "hello"; // N.B. s[] is 6 chars long including the null terminator
testing(s);
printf("%s\n", s);
} // main
Then you can change testing to overwrite the contents of the array pointed to by its parameter s:
#include <string.h>
void testing(char *s) {
strcpy(s, "hi");
} // testing
I have made use of the strcpy standard library function in the above version of testing.
It is up to you to ensure that you do not write too many chars to the array pointed to by s.
The length of array s in main has been automatically set to 6 by the initializer "hello" (5 characters plus a null terminator character). You can set the length of the array explicitly if you need to overwrite more than 6 chars including the null terminator:
char s[100] = "hello"; // s[100] has space for 99 characters plus a null terminator.
Functions receive only copies of argument values:
void f(int x) // x is a new variable that is initialized to the argument value.
{
x = x + 3; // Adds 3 to the local x.
printf("%d\n", x); // Prints 8.
}
int main(void)
{
int x = 5;
f(x); // Passes 5, not x, to f.
printf("%d\n", x); // Prints 5, not 8.
}
You can get a value back from a function by returning it:
int f(int x) // Function is changed to return int.
{
x = x + 3; // Adds 3 to the local x.
printf("%d\n", x); // Prints 8.
return x; // Returns new value.
}
int main(void)
{
int x = 5;
x = f(x); // Set x from the value returned by the function.
printf("%d\n", x); // Prints 8.
}
You can also get a value back from a function by having the function change the value of an object. To do this, you must provide the address of the object to the function:
void f(int *p) // p is a pointer to an int.
{
*p = *p + 3; // Adds 3 to the pointed-to int.
printf("%d\n", *p); // Prints 8.
}
int main(void)
{
int x = 5;
f(&x); // Passes address of x to f.
printf("%d\n", x); // Prints 8.
}
If you want a function to change a pointer, you can pass the address of a pointer:
void f(char **p) // p is a pointer to a pointer to a char.
{
*p = "hi" // Sets *p to point to (first character of) "hi".
printf("%s\n", x); // Prints "hi".
}
int main(void)
{
char *s = "hello"; // Sets s to point to (first character of) "hello".
f(&s); // Passes address of s to f.
printf("%s\n", x); // Prints "hi".
}

Memcpy from a double pointer in c

I have a pointer A, which is passed into a function with address, say myfunc(&A).
In the function myfunc(char **A) {
I want to copy memory from A[2 to n] to C[2 to n] }
I tried memcpy(&c[2], &(*A)[2], 20);
I am getting the address copied into c rather than the actual info in A.
To copy memory from A[2 to n] to C[2 to n] (from question)
A is a char **, it points to a number of char *.
The 3rd char * is A[2]. You want to use the address of that element in memcpy.
So the line should be
memcpy(&c[2], &A[2], N);
where N is, according to your text, (n-2+1)*sizeof(char *). memcpy size argument ignores the type of what it copies, therefore the total size of what to be copied is to be provided. You want to copy from 2 to n, that makes n-2+1 elements. Each element is a char * which size is sizeof(char *).
-- following comment --
While not clear from the question, if you want to dereference A twice, you copy characters... like
memcpy(&c[2], &A[0][2], 20 /* 20 chars */);
C would be a char *.
memcpy(c+2, *A+2, 20) should be enough.
Here is a test program:
#include <stdio.h>
#include <string.h>
char c[10] = { 'a', 'b' };
void myfunc(char **A)
{
memcpy(c+2, *A+2, 8);
}
int
main(void)
{
char *A = "ABCDEFIJK";
printf("Before: %s\n", c);
myfunc(&A);
printf("After : %s\n", c);
return 0;
}
Run:
$ ./a.out
Before: ab
After : abCDEFIJK

Correct implementation of comparator function in C not working as expected

I was testing an implementation of a comparator function. So here's my code that worked
#include <stdio.h>
#include <string.h>
int compare_names(const void* a, const void* b)
{
char* sa = (char*) a;
char* sb = (char*) b;
return strcmp(sa, sb);
}
int main()
{
char *a = "Bianca";
char *b = "Ana";
printf("Comparing %s with %s returns: %i\n", a, b, compare_names(a, b));
return 0;
}
But I don't think it's right as a and b arguments at compare_names function should turn out to be a pointer to a pointer of char. As pointed in a book I've read, the correct code for the compare_names function would be
int compare_names(const void* a, const void* b)
{
char** sa = (char**) a;
char** sb = (char**) b;
return strcmp(*sa, *sb);
}
But when I ran the code I got a segmentation fault (core dumped).
What am I missing here?
EDIT: I'm using gcc on Linux x64.
#include <stdio.h>
#include <string.h>
int compare_names(const void* a, const void* b)
{
char** sa = (char**) a;
char** sb = (char**) b;
return strcmp(*sa, *sb);
}
int main()
{
char *a = "Bianca";
char *b = "Ana";
printf("Comparing %s with %s returns: %i\n", a, b, compare_names(&a, &b));
return 0;
}
Now it's ok. You have to put the address of a and b in the printf parameters, since there are casted to char**.
char** sa = (char**) a; This line says: "If you direference twice your sa you will end up with a char" The problem is that since your a is a pointer to char you can not direference it twice. So the casting you are doing is generally wrong.
When casting, the compiler trys to interpret your *a which is a char as a pointer to char so when the conversion is performed your *sa ends up being a BadPtr since it fails to convert from char to char *.
So in your strcmp() you have two BadPtr.
You are passing char* arguments, not char** arguments. The example code you posted showing char** does the following:
1. Change generic pointer to a pointer to a string.
2. Compare the strings by dereferencing the char** arguments, meaning you're passing char* arguments to strcmp and return the result.
But you passed char* arguments to your comparison function, so the dereferencing ends up passing arguments of type char to strcmp. Since it expects pointers, the char is interpreted as a memory address. Comparing "hello" to "bye" actually compares the string at address 0x67 to the string at address 0x62, which will segfault.
Pass &a and &b to your comparison function to make it not segfault.
Both versions should work, however, for the second version of the "campare_names" function, you should pass an aditional pointer to each of the char pointers when calling the function.
However your version of the function is correct, it only makes sence to use double pointer parameters, when you are expecting that a function wil alter the pointer position or data being pointed. In this case, since the strcmp function only reads the char* data and doesn't make any changes to it, you don't need an aditional pointer.

Why does my C program crash when assigning a value to an int pointer?

I am trying to have a function take some integer pointers passed from my main() function and assign values to them. However, my program crashes when assigning values. Here is my code:
int computeMoveLocation(int* r, int* c, char* board)
{
//some code up here
*r = 0; //This breaks the program
*c = 0;
}
I'm not trying to change the address of the pointer--I'm trying to change the value of the integer being pointed to. However, I am apparently doing something wrong.
Any help would be greatly appreciated.
EDIT:
Here is the relevant code from main(). Please let me know if I should include anything else as well.
int main()
{
//initialization code
//...
while (1)
{
switch (MACHINE_STATE)
{
case COMPUTER_MOVE :
{
//check rows for three Xs
//check columns for three Xs
//check diagonals for three Xs
//otherwise, move anywhere else
int *r, *c;
computeMoveLocation(r, c, board);
computerMove(*r,*c, board);
PREVIOUS_STATE = COMPUTER_MOVE;
MACHINE_STATE = HUMAN_MOVE;
break;
}
//Other cases
}//end switch
}//end while
}//end main
You are passing in pointers but you didn't allocate memory. So they are pointing at a random location in memory.
int computeMoveLocation(int* r, int* c, char* board) {
//some code up here
*r = 0; //This breaks the program
*c = 0;
}
Bad main :
int main() {
int *r;
int *c;
char *board;
// bad, passing in pointers but didn't allocate memory
computeMoveLocation(r, c, board);
return 0;
}
Good main #1:
int main() {
int r = 5;
int c = 5;
char board = 'a';
// fine, passing address of variables on stack
computeMoveLocation(&r, &c, &board);
return 0;
}
Good main #2:
int main() {
int *r = malloc(sizeof(int));
*r = 5;
int *c = malloc(sizeof(int));
*c = 5;
char *board = malloc(sizeof(char));
*board = 'a';
// fine, passing pointers that point to heap
computeMoveLocation(r, c, board);
free(r);
free(c)
free(board);
return 0;
}
int *r, *c;
computeMoveLocation(r, c, board);
computerMove(*r,*c, board);
You define a pointer but don't make it point to anything. Thus, it is a wild or uninitialized pointer; accessing *r as you do in computeMoveLocation will cause undefined behaviour (in your case, a crash).
You have to either initialize the pointer to point at something known, or just pass the address of an existing int:
int r, c;
computeMoveLocation(&r, &c, ...);
or
static int x, y; // static: only one instance of the variable exists
int *r = &x; // initialize pointers
int *c = &y;
computeMoveLocation(r, c, ...);
or
int *r = malloc(sizeof(int));
int *c = malloc(sizeof(int));
computeMoveLocation(r, c, ...);
In that last case, make sure to free the memory afterwards.
You can always pass a pointer and modify the value that the pointer is pointing to. That is how pointers are supposed to be used. But, you should also be careful to see if the pointer does really points to something or not. The pointer should contain a valid address, the value at whose location you can change. If you don't ensure that, then Undefined Behavior will result.
For Example, when you call your computeMoveLocation function, the address which you are passing should either be of stack or of heap. You can see the code below to understand it.
First possibility
int r, c;
char board;
computeMoveLocation(&r,&c, &board);
Second Possibility
int *r, *c;
char *board;
r = malloc(sizeof(int));
c = malloc(sizeof(int));
board = malloc(sizeof(char));
computeMoveLocation(r,c,board);
Please note that char * is also generally used to pass an address to array of charaters, but, in a such a usage, generally it is ensure that it is null terminated or an accompanying length of the array is also passed.
You can anyway get more details on passing aroung pointers by a simple google search.
EDIT
Now, that you have posted your code which calls computeMoveLocation, you see that you should modify your code according to the Second Possibility shown above, since you are declaring r and c as pointers or you should declare them as integers and call as per the First Possibility shown above. But, you are not doing the same which causes the undefined behavior.
Also, in the above examples, I have allocated memory for board, but, in your case, if it originates at some other place and if it has been handled appropriately there, then it need not be malloced.

Resources