In short, is there any way I can take in a
char *inputinto a function and modify its original memory address without using something likememcpyfrom string.h?
Yes, you can. Your function modifyCharArray is doing the right thing. What you are seeing is caused by that fact that
char *test = "Bad";
creates "Bad" in read only memory of the program and test points to that memory. Changing it is cause for undefined behavior.
If you want to create a modifiable string, use:
char test[] = "Bad";
Answer from R Sahu on Stack OverflowModify char array passed to a function, C - Stack Overflow
c - Cannot modify char array - Stack Overflow
Changing a character array inside a function in C - Stack Overflow
c++ - C+ how to change array of chars in function - Stack Overflow
Your program has several errors. Assuming the string length. Not allowing for, or writing , the nul terminator. Not returning the pointer. Using == where you mean =. Trying to return a local variable.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *echanger(char *word) {
int len = strlen(word);
int i;
char *final = malloc(len+1);
for(i=0; i<=len; i++) { // include terminator
if(word[i] == 'e')
final[i] = 'a';
else
final[i] = word[i];
}
return final;
}
int main(){
char a[] = "helle";
char *news;
news = echanger(a);
printf("new string is: %s\n", news);
free(news); // was from malloc
return 0;
}
Program output:
new string is: halla
You are using equality (==) operator instead of for assignment (=) operator. Change final[i] == 'a' to final[i] = 'a'.
If I rewrite the function with the changes then it will be -
char echanger(char word[]){
int total = 0;
int i;
char final[5];
for(i=0;i<5;i++){
if(word[i]=='e'){
final[i] = 'a';
}
else{
final[i] = word[i];
}
}
return final;
}
Hope it will help.
Thanks a lot.
dst is allocated in main. To modify that allocation in a function, you can return the new pointer or pass a pointer to pointer. Since you return another pointer, you must pass a pointer to pointer char **dest and make a few changes in the function to accommodate that change.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *my_strcat ( char **dest, const char * src) {
char *tab = malloc ( sizeof ( char) * (strlen ( *dest) + strlen ( src) + 1));//dereference dest
if ( NULL == tab)
return NULL;
strcpy ( tab, *dest);//dereference dst
strcat ( tab, src);
free ( *dest);//dereference dest
*dest = malloc ( sizeof ( char) * ( strlen ( tab) + 1));//dereference dest
strcpy ( *dest, tab);//dereference dest
return tab;
}
int main(int argc, char **argv) {
char *dst = NULL, *src = NULL, *r = NULL;
src = malloc ( sizeof ( char) * 100);
strcpy ( src, "fifty");
dst = malloc ( sizeof ( char) * 100);
strcpy ( dst, "four");
r = my_strcat ( &dst, src);//use address of dst
printf ( "%s\n", r);
printf ( "%s\n", dst);
free ( r);
free ( dst);
free ( src);
return 0;
}
There are several problems in your code. You can use tools like valgrind, clang-tidy to help you.
Here is your code with line numbers
1 /* -*- compile-command: "gcc prog.c; ./a.out"; -*- */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 char *my_strcat(char *dest, const char *src)
7 {
8 char *tab = (char *)malloc(sizeof(char) * (strlen(*dest) + strlen(src) + 1));
9 if (NULL == tab)
10 return NULL;
11 strcpy(tab, dest);
12 strcpy(tab, src);
13 free(dest);
14 dest = (char *)malloc(sizeof(char) * (strlen(tab) + 1));
15 strcpy(dest, tab);
16 return tab;
17 }
18
19 int main(int argc, char **argv)
20 {
21 char *dst = NULL, *src = NULL, *r = NULL;
22 int i;
23 src = malloc(sizeof(char) * 100);
24 strcpy(src, "fifty");
25
26 dst = malloc(sizeof(char *) * 100);
27 strcpy(src, "four");
28
29 r = my_strcat(dst, src);
30 printf("%s\n", r);
31 printf("%s\n", dst);
32
33 free(r);
34 free(dst);
35 free(src);
36
37 return 0;
38 }
Let's use cland-tidy to perform a static analysis:
clang-tidy-7 prog.c --
prints a bunch of messages:
8 warnings generated. /home/picaud/Temp/prog.c:8:46: warning: 1st function call argument is an uninitialized value [clang-analyzer-core.CallAndMessage] char *tab = (char *)malloc(sizeof(char) * (strlen(*dest) + strlen(src) + 1)); ^ /home/picaud/Temp/prog.c:26:9: note: Storing uninitialized value dst = malloc(sizeof(char *) * 100); ^ /home/picaud/Temp/prog.c:29:7: note: Calling 'my_strcat' r = my_strcat(dst, src); ^ /home/picaud/Temp/prog.c:8:46: note: 1st function call argument is an uninitialized value char *tab = (char *)malloc(sizeof(char) * (strlen(*dest) + strlen(src) + 1)); ^ /home/picaud/Temp/prog.c:8:53: warning: incompatible integer to pointer conversion passing 'char' to parameter of type 'const char *';etc...
The first lines explain that dest is not initialized, you can track back it to:
26 dst = malloc(sizeof(char *) * 100);
27 strcpy(src, "four");
which is certainly a bug and have to be remplaced by
26 dst = malloc(sizeof(char *) * 100);
27 strcpy(dst, "four");
Now you can rerun clang-tidy. The first message is:
/home/picaud/Temp/prog.c:8:53: warning: incompatible integer to pointer conversion passing 'char' to parameter of type 'const char *'; remove * [clang-diagnostic-int-conversion] char *tab = (char *)malloc(sizeof(char) * (strlen(*dest) + strlen(src) + 1)); ^~~~~
Which immediatly points to another bug, replace:
8 char *tab = (char *)malloc(sizeof(char) * (strlen(*dest) + strlen(src) + 1));
by
8 char *tab = (char *)malloc(sizeof(char) * (strlen(dest) + strlen(src) + 1));
you also have
/home/picaud/Temp/prog.c:26:9: warning: Result of 'malloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'char *' [clang-analyzer-unix.MallocSizeof]
dst = malloc(sizeof(char *) * 100);
^
hence you must replace:
dst = malloc(sizeof(char *) * 100);
by
dst = malloc(sizeof(char) * 100);
reruning clang-tidy still shows some problems:
/home/picaud/Temp/prog.c:27:3: note: Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
/home/picaud/Temp/prog.c:31:3: warning: Use of memory after it is freed [clang-analyzer-unix.Malloc]
printf("%s\n", dst);
^
/home/picaud/Temp/prog.c:26:9: note: Memory is allocated
dst = malloc(sizeof(char) * 100);
^
/home/picaud/Temp/prog.c:29:7: note: Calling 'my_strcat'
r = my_strcat(dst, src);
^
/home/picaud/Temp/prog.c:9:3: note: Taking false branch
if (NULL == tab)
^
/home/picaud/Temp/prog.c:13:3: note: Memory is released
free(dest);
^
/home/picaud/Temp/prog.c:29:7: note: Returning; memory was released via 1st parameter
r = my_strcat(dst, src);
^
/home/picaud/Temp/prog.c:31:3: note: Use of memory after it is freed
printf("%s\n", dst);
I let you check all this. On my side following these warnings I get this new version for your code:
/* -*- compile-command: "gcc prog.c; ./a.out"; -*- */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *my_strcat(char *dest, const char *src)
{
char *tab = (char *)malloc(sizeof(char) * (strlen(dest) + strlen(src) + 1));
if (NULL == tab)
return NULL;
strcpy(tab, dest);
strcpy(tab+strlen(dest), src);
return tab;
}
int main(int argc, char **argv)
{
char *dst = NULL, *src = NULL, *r = NULL;
int i;
src = malloc(sizeof(char) * 100);
strcpy(src, "fifty");
dst = malloc(sizeof(char) * 100);
strcpy(dst, "four");
r = my_strcat(dst, src);
printf("%s\n", r);
printf("%s\n", dst);
free(r);
free(dst);
free(src);
return 0;
}
when run, this code prints:
gcc prog.c; ./a.out
fourfifty
four
You can use valgrind to check that there is no memory leaks:
valgrind ./a.out
==4023== Memcheck, a memory error detector
==4023== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==4023== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==4023== Command: ./a.out
==4023==
fourfifty
four
==4023==
==4023== HEAP SUMMARY:
==4023== in use at exit: 0 bytes in 0 blocks
==4023== total heap usage: 4 allocs, 4 frees, 1,234 bytes allocated
==4023==
==4023== All heap blocks were freed -- no leaks are possible
==4023==
==4023== For counts of detected and suppressed errors, rerun with: -v
==4023== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Good learning!
You cannot use character array like that after declaration. If you want to assign new value to your character array, you can do it like this: -
strcpy(message, "bar");
Assignments like
message[] = "bar";
or
message = "bar";
are not supported by C.
The reason the initial assignment works is that it's actually array initialization masquerading as assignment. The compiler interprets
char message[]="foo";
as
char message[4] = {'f', 'o', 'o', '\0'};
There is actually no string literal "foo" involved here.
But when you try to
message = "bar";
The "bar" is interpreted as an actual string literal, and not only that, but message is not a modifiable lvalue, ie. you can't assign stuff to it. If you want to modify your array you must do it character by character:
message[0] = 'b';
message[1] = 'a';
etc, or (better) use a library function that does it for you, like strcpy().
The [] operator binds tighter then the *-operator, so change
*b[0] = 0x12;
to
(*b)[0] = 0x12;
Alternatively change
void changeBuff(unsigned char ** b)
{
*b[0] = 0x12;
*b[1] = 0x34;
}
to
void changeBuff(unsigned char * b)
{
b[0] = 0x12;
b[1] = 0x34;
}
and instead of calling it like this
changeBuff(&buf);
call it like this
changeBuff(buf);
Unrelated to your issue:
- There is no need to cast from/to
void-pointers in C. sizeof (char)equals 1 by definition.
So this line
unsigned char * buf = (unsigned char *)malloc(sizeof(unsigned char) * 2);
is equal to this
unsigned char * buf = malloc(2);
A more robust version would be
unsigned char * buf = malloc(2 * sizeof *buf);
which would survive changing the type of where buf points to.
Because of operator precedence, *b[0] is equivalent to *(b[0]), which is not you want.
Adding a pair of parentheses around *b is a solution:
(*b)[0] = 0x12;
1.
name="Messi";
You can´t assign a char array with a string unless at its initialization, which is done with:
char name[]="Ronaldo";
Rather use strcpy() (Header string.h) -> strcpy(name,"Messi"); instead.
Consider that the array name needs to be capable of holding the new-assigned string + the null terminator, which is in this case provided because the string "Ronaldo" has more characters than any of the following. If that would not be the case you have to define name with an appropriate amount of characters or choose a name which is bigger than anyone else or the program would cause an overflow of data in memory.
2.
Note that the switch statement doesn´t make sense if choice is always 0 because you have never read input for choice.
Also the cases to the switch are not enclosed by { and } which should give you a compilation error.
3.
choice is initialized by a character. While this is permissible, it does not make sense in this case and confuses readers of your code. Rather use int choice = 0;
Corrected code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char name[]="Ronaldo";
int choice=0;
printf("Select Player\n");
printf("1.Messi\n2.Suarez\n3.Neymar\n4.Dembele\n5.Muller\n\n");
scanf("%d",&choice);
switch(choice)
{
case 1:
printf("\nMessi is Selected");
strcpy(name,"Messi");
break;
case 2:
printf("\nSuarez is Selected");
strcpy(name,"Suarez");
break;
case 3:
printf("\nNeymar is Selected");
strcpy(name,"Neymar");
break;
case 4:
printf("\nDembele is Selected");
strcpy(name,"Dembele");
break;
case 5:
printf("\nMuller is Selected");
strcpy(name,"Muller");
break;
default:
printf("Exit");
exit(1);
}
printf("\nPlayer changed to %s",name);
return 0;
}
Output:
/a.out
Select Player
1.Messi
2.Suarez
3.Neymar
4.Dembele
5.Muller
2 // Input from User
Suarez is Selected
Player changed to Suarez
The problem is that
char name[]="Ronaldo";
gives you an array of chars. That's not what you want because an array of char doesn't allow simple assignment. For char arrays you need to use strcpy.
However - what you want is a pointer to char - like:
char* name="Ronaldo";
Then you can do simple assignments like:
char* name="Ronaldo";
printf("My player is %s\n", name);
name = "Eriksen";
printf("My player is %s\n", name);
A char-pointer can be directly assigned to point to any string literal.
Besides that you never get any user input.
And notice that switch statement has a default- like:
switch(choice)
{
case 1:
// do some things for input 1
break;
case 2:
// do some things for input 2
break;
default:
// do some things for all other values
break;
}
Is it safe to pass char arrays as string literals into functions? Take the following function signature:
char *fgets(char *str, int n, FILE *stream)
fgets accepts char * and not a char array? So suppose I have a char array, say char string[3], and I pass it into the the aforementioned function.
Here is a minimal example:
#include <stdio.h
#include <string.h>
int main() {
char string[10];
fgets(string, 10, stdin);
string[strcspn(string, "\n")] = 0;
printf("%s", string);
}
Is passing in string, which is a char array, into a function, fgets in this case, that accepts string literals safe?
The = operator is not defined to copy the contents of one array to another. You either have to copy each array element individually in a loop:
for ( size_t i = 0; i < num_elements; i++ )
dst[i] = src[i];
or you have to call a library function like strcpy (for arrays that contain strings) or memcpy (for arrays that don't contain strings), which does pretty much the same thing under the hood.
Arrays and array expressions in C are weird compared to other aggregate types like struct or union; as part of that weirdness, array expressions are not allowed to be the target of an assignment operator. Under most circumstances, an expression of type "array of T" is converted, or "decays", to an expression of type "pointer to T" and the value of the expression is the address of the first element of the array.
This isn't arbitrary - Ritchie had a reason for making arrays behave this way - but it doesn't make it any less weird.
When trying to apply the same concept with an array of character arrays, you can't change the values
Yes you can, just not the way you are doing it. You can't assign one array to another. But you can use strcpy() instead to copy characters from one array to another, eg:
strcpy(stuff[i], "Not Cool");
Or better, strncpy(), eg:
strncpy(stuff[i], "Not Cool", 20);
As noted, in C a string is an array of characters. So, you can access the individual characters like you access any array. For your task what you need to do is
char names[100][20];
//Now this declares 100 strings of size 20 each.
//To access a single character in the position '4' from string 0 you can write
printf("%c",names[0][3]);
//To modify the string in position 'i' you will use
names[i][strlen(names[i])-1]='\0';
The last line is very similar to what you have written for a single string.
With the first index 'i' you access the string in that position. and with the second index you access a particular character of that string.
Try this:
#include <stdio.h>
#include <string.h>
int main(void)
{
char names[10][10];
char c = 'A';
for(int index = 0; i < strlen(names) - 1)
{
names[0][index] = c++;
}
names[i][strlen(names[i])-1]='\0';
printf("%s", namws[0]);
return 0;
}
Hello, I'm trying to make a simple function to remove the backslashes of a date format for homework.
#include <stdio.h>
char* changeDateFormat(char** date);
int main()
{
char* dateToFormat = "12/2/2024";
changeDateFormat(&dateToFormat);
printf("%s\n", dateToFormat);
return 0;
}
char* changeDateFormat(char** date)
{
size_t i = 0;
char* aux = *date;
while(*(aux + i) != '\0){
if(*(aux + i) == '/'){
*(aux + i) = '-';
}
i++;
}
return aux;
}But when I run this, it runs int SIGSEGV. I know that when passing a pointer to char by reference, dereferecing directs to an string literal which causes undefined behaviour. But is there anyway to avoid that without allocating dynamic memory and copying the string? Thanks.
PS: I must add, that the professor is insistent that we mostly use pointers to handle strings or any arrays for that matter. If I had done it, I would have foregone that additional complication and just use an array.
When you write a "string" in your source code, it gets written directly into the executable because that value needs to be known at compile time (there are tools available to pull software apart and find all the plain text strings in them). When you write char *a = "This is a string", the location of "This is a string" is in the executable, and the location a points to, is in the executable. The data in the executable image is read-only.
What you need to do (as the other answers have pointed out) is create that memory in a location that is not read only--on the heap, or in the stack frame. If you declare a local array, then space is made on the stack for each element of that array, and the string literal (which is stored in the executable) is copied to that space in the stack.
char a[] = "This is a string";
you can also copy that data manually by allocating some memory on the heap, and then using strcpy() to copy a string literal into that space.
char *a = malloc(256);
strcpy(a, "This is a string");
Whenever you allocate space using malloc() remember to call free() when you are finished with it (read: memory leak).
Basically, you have to keep track of where your data is. Whenever you write a string in your source, that string is read only (otherwise you would be potentially changing the behavior of the executable--imagine if you wrote char *a = "hello"; and then changed a[0] to 'c'. Then somewhere else wrote printf("hello");. If you were allowed to change the first character of "hello", and your compiler only stored it once (it should), then printf("hello"); would output cello!)
No, you cannot modify it, as the string can be stored in read-only memory. If you want to modify it, you can use an array instead e.g.
char a[] = "This is a string";
Or alternately, you could allocate memory using malloc e.g.
char *a = malloc(100);
strcpy(a, "This is a string");
free(a); // deallocate memory once you've done