Can anyone please help me? I need to remove the first character from a const char * in C.
For example, const char * contents contains a 'x' character as the first character in the array. I need to detect and eliminate this character, modifying the original variable after its been "sanitized".
Can anyone suggest how to achieve it? I'm completely new to C (though I know Java), and just can't seem to figure it out.
Note: I already referred to these, and still not able to figure out:
How to remove first character from C-string? - this tell how to remove when the input is char * contents
AND
Difference between char* and const char*?
it mentions that const char* is a mutable pointer but points to immutable character/string
What I tried below it works, but why it works?(it should not able to modify the immutable char array contents value "xup")
#include <stdio.h>
int main()
{
char input[4] = "xup";
removeLeadingX(input);
return 0;
}
int removeLeadingX(const char * contents)
{
//this if condition is something I have to add
//can't modify other code (ex: the method receives const char * only)
if(contents[0] == 'x'){
contents++;
}
printf(contents);//up - why immutable string "xup" updated to "up"?
return 0;
}
You can't remove anything from the const char object.
You need to make a copy of the string and then modify and use the copy
const char *original = "Hello world!";
char *copy = strdup(original);
copy[strlen(copy) - 1] = 0; //removing `!`
You can modify the pointer to reference other element of the string. But you lose the original pointer and actually do not remove anything from the string.
const char *original = "Hello world!";
original = strchr(original, 'w');
printf("%s\n", original);
What I tried below it works, but why it works?(it should not able to
modify the immutable char array contents)
In your example you modify the pointer not the object referenced by the pointer. It is OK.
If you declare this function as
void removeLeadingX(const char * const contents)
the pointer will also be const and your code will not compile.
Do you need to remove the leading character, or simply ignore it.
Here's an example of what the function is doing (simply changing the pointer)
int main() {
char input[4] = "xup";
char *p = input;
printf( "advance\n" );
p = p + 1;
printf( "input: '%s'\n", input );
printf( "p: '%s'\n", p );
printf( "retreat\n" );
p = p - 1;
printf( "input: '%s'\n", input );
printf( "p: '%s'\n", p );
printf( "nothing has been removed or shifted except the pointer 'p'\n" );
return 0;
}
Output:
advance
input: 'xup'
p: 'up'
retreat
input: 'xup'
p: 'xup'
nothing has been removed or shifted except the pointer 'p'
The function declaration int removeLeadingX(const char * contents) doesn't make any sense. Either the function should modify the passed string "in place", in which case the function should be:
void removeLeadingX (char* contents)
Or the function should store a modified copy of the original (immutable) string somewhere, in which case the function could be:
void removeLeadingX (char* new_str, const char* old_str)
These could be implemented as:
void removeLeadingX (char* contents)
{
if(contents[0]) == 'x')
memmove(&contents[0], &contents[1], 1);
}
Or:
void removeLeadingX (char* new_str, const char* old_str)
{
if(old_str[0] == 'x')
{
// assuming new_str points at a caller-allocated array:
strcpy(new_str, &old_str[1]);
}
}
Considering that the original object in main is not const, you can modify the array using a dirty trick to avoid warnings:
#include <stdio.h>
#include <string.h>
int removeLeadingX(const char *contents)
{
if (contents[0] == 'x')
{
union {const char *constant; char *not_constant;} dummy = {contents};
memmove(dummy.not_constant, contents + 1, strlen(contents));
}
printf("%s\n", contents);
return 0;
}
int main(void)
{
char input[4] = "xup";
removeLeadingX(input);
return 0;
}
Related
Why this works:
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char st[] = "Hello";
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
And this doesn't:
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char*st = "Hello";
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
In first I initialized my string using:
char st[]="Hello"; (using array)
And in latter I used:
char*st="Hello"; (using pointer)
I'm kind of getting confused between these 2 initialization types, what's the key difference between declaring a string by using char st[]="Hello"; and by using char*st = "Hello";.
With char st[] = "Hello";, st[] is a modifiable array of characters. The call slice(st, 1, 6); takes the array st and converts to a pointer to the first element of the array. slice() then receives that pointer, a pointer to modifiable characters.
With char *st = "Hello";, st is a pointer that points to a string literal "Hello". With the call slice(st, 1, 6);, the function receives a copy of the pointer - a pointer to the string literal. Inside slice(), code st[i] = ... is attempting to modify a string literal, that is undefined behavior (UB). It might work, it might fail, it might work today and fail tomorrow - it is not defined.
Do not attempt to modify a string literal.
... passing strings to a function ...
In both cases, code does not pass a string to slice(), but a pointer to a string. Knowing that subtle distinction helps in understanding what is truly happening.
This is an artifact of old syntax in C:
char * s = "Hello world!";
is a non-const character pointer to const memory. It is still permitted by syntax, but the string is still not a mutable object. To be pedantic it should really be written as:
const char * s = "Hello world!";
In contrast:
char s[] = "Hello world!";
allocates a local (on the stack), mutable array and copies the string data to it (from wherever the non-mutable copy is stored in memory). Your function can then do as it likes to your local copy of the string.
The type char [] is different from the type char* (char* is a variable - int. but char[] is an array which is not a variable). However, an array name can be used as a pointer to the array.
So we can say that st[] is technically similar to *str .
the problem in the 2nd version of your code
If you have read-only strings then you can use const char* st = "hello"; or simply char* st = "hello"; . So the string is most probably be stored in a read-only memory location and you'll not be able to modify it.
However, if you want to be able to modify it, use the malloc function:
char *st= (char*) malloc(n*sizeof(char)); /* n-The initial size that you need */
// ...
free(st);
**So to allocate memory for st, count the characters ("hello"-strlen(st)=5) and add 1 for this terminating null character , and functions like scanf and strcpy will add the null character;
so the code becomes :
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char *st =malloc(6*sizeof(char)) ;
const char *cpy="hello";
strcpy(st, cpy); /* copies the string pointed by cpy (including the null character) to the st. */
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
you can fill your string also by a for loop or by scanf() .
in the case of a large allocation you must end your code with free(st);
this program it suppose to print Hello World but guess what exited, segmentation fault why is that happening ?
#include <stdio.h>
#include <string.h>
char f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char*str1 = "hello ";
char*str2 = "world!";
str1=f(str1, str2);
printf("%s", str1);
return 0;
}
You are not allowed to modify string literals. Use arrays with enough elements instead for strings to be modified.
Also assigning the return value of f to str1 is a bad idea because no return statement is executed in the function f and using its return value invokes undefined behavior. The return type should be changed to void if you are not going to return anything.
#include <stdio.h>
#include <string.h>
void f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char str1[16] = "hello ";
char*str2 = "world!";
f(str1, str2);
printf("%s", str1);
return 0;
}
First of all, this:
char*str1 = "hello ";
is a pointer to constant data, which means that you can't change the string "hello "
This is a constant pointer to variable data:
char str1[] = "hello ";
Which means that str1 always points to the same address in memory, but you can modify the content of that chunk of memory.
However str1 will have a fixed size of 7 characters (don't forget to count \0), so you can't append another string to it.
You could define a size #define SIZE 20 large enough to store both strings and declare
char str1[SIZE] = "hello ";
Or you could declare str1 as a VLA (variable length array) after having declared the string to append:
char*str2 = "world!";
char str1[strlen("hello ")+strlen(str2)+1] = "hello ";
Where the +1 is for \0.
Is it important that you copy characters one by one?
Because if it's not you can just copy one string to another like this.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char str1[] = "hello ";
char str2[] = "world!";
char *result = malloc(strlen(str1) + strlen(str2) + 1);
strcpy(result, str1);
strcat(result, str2);
printf("%s", result);
return 0;
}
First you are not allowed to change a constant string, that is undefined behaviour.
Secondly your f function has no return statement and thus returns random data, making the str1 variable in main point to random memory. Using it then also has undefined behaviour.
To fix it you should allocate new memory and concatenate the string into that
char* f(const char *s1, const char *s2)
{
char *s = malloc(strlen(s1) + strlen(s2) +1);
if (s) {
strcpy(s, s1);
strcat(s, s2);
}
return s;
}
The extra one byte allocated is for the terminating zero.
Both arguments are const as there is no reason to modify them, which allows both arguments to be literal strings.
For starters you may not change string literals (in this case the string literal pointed to by the pointer str1).
char*str1 = "hello ";
char*str2 = "world!";
Any attempt to change a string literal results in undefined behavior.
You need to allocate a character array large enough to store the result string with the appended string literal pointed to by the pointer str2.
Secondly there is already the standard C function strcat that performs the required task. If you have to write such a function yourself then it seems you should not use any string function as for example strlen.
And the return type char of your function does not make a sense. And moreover actually your function returns nothing.
So this assignment
str1=f(str1, str2);
results in undefined behavior.
The function and the program in whole can be written the following way without using standard string functions.
#include <stdio.h>
char * f( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) );
return s1;
}
int main(void)
{
char s1[14] = "Hello ";
char *s2 = "World!";
puts( f( s1, s2 ) );
return 0;
}
The program output is
Hello World!
Pay attention to that the second function parameter shall have the qualifier const because the pointed string is not changed within the function. And the function return type should be char * that is the function should return the result string.
I am trying to write a method that takes a string and splits it into two strings based on a delimiter string, similar to .split in Java:
char * split(char *tosplit, char *culprit) {
char *couple[2] = {"", ""};
int i = 0;
// Returns first token
char *token = strtok(tosplit, culprit);
while (token != NULL && i < 2) {
couple[i++] = token;
token = strtok(NULL, culprit);
}
return couple;
}
But I keep getting the Warnings:
In function ‘split’:
warning: return from incompatible pointer type [-Wincompatible-pointer-types]
return couple;
^~~~~~
warning: function returns address of local variable [-Wreturn-local-addr]
... and of course the method doesn't work as I hoped.
What am I doing wrong?
EDIT: I am also open to other ways of doing this besides using strtok().
A view things:
First, you are returning a pointer to a (sequence of) character(s), i.e. a char
* rather than a pointer to a (sequence of) pointer(s) to char. Hence, the return type should be char **.
Second, you return the address of a local variable, which - once the function has finished - goes out of scope and must not be accessed afterwards.
Third, you define an array of 2 pointers, whereas your while-loop may write beyond these bounds.
If you really want to split into two strings, the following method should work:
char ** split(char *tosplit, char *culprit) {
static char *couple[2];
if ((couple[0] = strtok(tosplit, culprit)) != NULL) {
couple[1] = strtok(NULL, culprit);
}
return couple;
}
I'd caution your use of strtok, it probably does not do what you want it to. If you think it does anything like a Java split, read the man page and then re-read it again seven times. It is literally tokenizing the string based on any of the values in delim.
I think you are looking for something like this:
#include <stdio.h>
#include <string.h>
char* split( char* s, char* delim ) {
char* needle = strstr(s, delim);
if (!needle)
return NULL;
needle[0] = 0;
return needle + strlen(delim);
}
int main() {
char s[] = "Fluffy furry Bunnies!";
char* res = split(s, "furry ");
printf("%s%s\n", s, res );
}
Which prints out "Fluffy Bunnies!".
First of all strtok modifies the memory of tosplit so be certain that, that's what you wish to do. If so then consider this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* NOTE: unsafe (and leaky) implementation using strtok
*
* *into must point to a memory space where tokens can be stored
* or if *into is NULL then it allocates enough space.
* Returns:
* allocated array of items that you must free yourself
*
*/
char **__split(char *src, const char *delim)
{
size_t idx = 0;
char *next;
char **dest = NULL;
do {
dest = realloc(dest, (idx + 1)* sizeof(char *));
next = strtok(idx > 0 ? NULL:strdup(src), delim);
dest[idx++] = next;
} while(next);
return dest;
}
int main() {
int x = 0;
char **here = NULL;
here = __split("hello,there,how,,are,you?", ",");
while(here[x]) {
printf("here: %s\n", here[x]);
x++;
}
}
You can implement a much safer and non leaky version (note the strdup) of this but hopefully this is a good start.
The type of couple is char** but you have defined the function return type as char*. Furthermore you are returning the pointer to a local variable. You need to pass the pointer array into the function from the caller. For example:
#include <stdio.h>
#include <string.h>
char** split( char** couple, char* tosplit, char* culprit )
{
int i = 0;
// Returns first token
char *token = strtok( tosplit, culprit);
for( int i = 0; token != NULL && i < 2; i++ )
{
couple[i] = token;
token = strtok(NULL, culprit);
}
return couple;
}
int main()
{
char* couple[2] = {"", ""};
char tosplit[] = "Hello World" ;
char** strings = split( couple, tosplit, " " ) ;
printf( "%s, %s", strings[0], strings[1] ) ;
return 0;
}
So, I have seen this strcpy implementation in C:
void strcpy1(char dest[], const char source[])
{
int i = 0;
while (1)
{
dest[i] = source[i];
if (dest[i] == '\0')
{
break;
}
i++;
}
}
Which to me, it even copies the \0 from source to destination.
And I have also seen this version:
// Move the assignment into the test
void strcpy2(char dest[], const char source[])
{
int i = 0;
while ((dest[i] = source[i]) != '\0')
{
i++;
}
}
Which to me, it will break when trying to assign \0 from source to dest.
What would be the correct option, copying \0 or not?
The code should look like as follows:
char * strcpy(char *strDest, const char *strSrc)
{
assert(strDest!=NULL && strSrc!=NULL);
char *temp = strDest;
while(*strDest++ = *strSrc++); // or while((*strDest++=*strSrc++) != '\0');
return temp;
}
You can NOT delete the second line char *temp = strDest; and directly return strDest. This will cause error for the returned content. For example, it will not return correct value (should be 22) will checking the length of returned char *.
char src_str[] = "C programming language";
char dst_str[100];
printf("dst_str: %d\n", strlen(strcpy(dst_str, src_str)));
Both copy the terminator, thus both are correct.
Note that strcpy2() does the assignment (the copying) first, then the comparison. So it will copy the terminator before realizing it did, and stopping.
Also, note that functions whose names start with str are reserved, so neither of these are actually valid as "user-level" code.
You're wrong. Both copy the \0 (NUL terminator) character. You have to copy the NUL terminator character always or your string will be broken: you'll never know when/where it ends.
Both copy the terminator, thus both are correct.
strcpy2() does the copying first, then the compares. Thus it will copy the terminator and stops.
The functions whose names start with str are reserved, so use any other variables or naming types
It is recommended not to advance the input pointers to the source and destination memory spaces, since the pointers will be used in main right away.
I've mentioned alternate methodical syntax, where in case someone might wonder the code output.
void strcpy1(char * s, char * p)
{
char * temp1 = s;
char * temp2 = p;
while(*temp1 != '\0')
{
*temp2 = *temp1;
temp1++;
temp2++;
}
*temp2 = '\0';
}
void main()
{
char * a = "Hello";
char b[10];
strcpy1(a,b);
printf("%s", b);
return 0;
}
Both strcpy1() and strcpy2() does the same. Both copy the NUL character to the end of the destination array.
Here is full implementation. You do not have to consider the \0 at the end in the first string, it will be copied automatically from the second string as per logic
//str copy function self made
char *strcpynew(char *d, char *s){
char *saved = d;
while ((*d++ = *s++) != '\0');
return saved; //returning starting address of s1
}
//default function that is run by C everytime
int main(){
//FOR STRCPY
char s1[] = "rahul"; //initializing strings
char s2[] = "arora"; //initializing strings
strcpynew(s1, s2);
printf("strcpy: %s\n", s1); //updated string after strcpy
}
You can use this code, the simpler the better !
Inside while() we copy char by char and moving pointer to the next. When the last char \0 will pass and copy while receive 0 and stop.
void StrCopy( char* _dst, const char* _src )
{
while((*_dst++ = *_src++));
}
char * strcpy(char *strDest, const char *strSrc)
{
assert(strDest!=NULL && strSrc!=NULL);
assert(strSrc + strlen(strSrc) < d || strSrc > strDest); // see note
char *temp = strDest;
while(*strDest++ = *strSrc++)
;
return temp;
}
// without the check on line 4, the new string overwrites the old including the null deliminator, causing the copy unable to stop.
Both copy the '\0'. That's what you have to do if you want to fully emulate the original strcpy
Assume that you have a link like http://1.1.1.1/test.mpg. Then you want to change it to http://1.1.1.1/test.mkv. How can you change "mpg" to "mkv" programmatically in C? I tried to use strtok and strcpy but I am not good in C so I couldn't do it.
The following is the solution, but there is one thing left to you for experimenting!
The malloc'ed memory is not free'd in the below code. Try it on your own!
One other drawback is, it does replace only the first occurrence of the string.. So you cna improve this code to replace all the occurrence of the string!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * strrep(char *str, char *o_s, char *n_s)
{
char *newstr = NULL;
char *c = NULL;
/* no substring found */
if ((c = strstr(str, o_s)) == NULL) {
return str;
}
if ((newstr = (char *) malloc((int) sizeof(str) -
(int) sizeof(o_s) +
(int) sizeof(n_s) + 1)) == NULL) {
printf("ERROR: unable to allocate memory\n");
return NULL;
}
strncpy(newstr, str, c-str);
sprintf(newstr+(c-str), "%s%s", n_s, c+strlen(o_s));
return newstr;
}
int main(void)
{
char str[] = "http://1.1.1.1/test.mpg";
char old_s[] = "mpg";
char new_s[] = "mkv";
char *str_new = strrep(str, old_s, new_s);
if (str_new != NULL) {
printf("Original : %s\n", str);
printf("Replaced : %s\n", str_new);
}
return 0;
}
$ gcc strrep.c
$ ./a.out
Original : http://1.1.1.1/test.mpg
Replaced : http://1.1.1.1/test.mkv
$
You shouldn't change a const char*. Changing it will lead to undefined behavior. Usually, a const is there for a reason.
That aside, you should create a new char*, copy the contents inside it, and modify that.
Changing a character from a const char * should not be allowed by the compiler, and if done via an explicit cast to char * will lead to undefined behaviour.
If you declare the string as an array that is stored either globally or on the stack:
char str[] = "http://1.1.1.1/test.mpg";
Then you are not dealing with const char * and altering characters is OK. Otherwise,
char *str = "http://1.1.1.1/test.mpg";
the string literal will possibly be stored in a read-only protected area of the process and an attempt to write there will most probably generate a protection fault.
A const char * pointer cannot and must not be changed. This is indicated by the const, that obviously tells that this pointer points to constant characters.
If you need to change something in this variable programatically your only choice is to first copy it to another variable of sufficient size and change that. For this you can just change the last few bytes by using array indexing. Something like this will work:
const char * url = "http://1.1.1.1/test.mpg";
char * url2;
url2 = malloc( strlen( url ) + 1 );
strcpy( url2, url ); // no need to use strncpy
url2[ strlen( url2 ) - 3 ] = 'm';
url2[ strlen( url2 ) - 2 ] = 'k';
url2[ strlen( url2 ) - 1 ] = 'v';
Note that in this case this only works so smoothely, because the length of "mkv" and "mpg" is the same. If it is not you need some more complicated techiques.