I am writing a C program in Unix and cannot figure out how to set an array element to NULL. I need to be able to do this to remove multiple characters from a string.
You can't assign null to specific char array index as value represented by that index is char instead of pointer. But if you need to remove specific character from given string, you can implement this as follows
void removeChar(char *str, char garbage) {
char *src, *dst;
for (src = dst = str; *src != '\0'; src++) {
*dst = *src;
if (*dst != garbage) dst++;
}
*dst = '\0';
}
Test Program
#include<stdio.h>
int main(void) {
char* str = malloc(strlen("abcdef")+1);
strcpy(str, "abcdbbbef");
removeChar(str, 'b');
printf("%s", str);
free(str);
return 0;
}
output
acdef
If you have a char[], you can zero-out individual elements using this:
char arr[10] = "foo";
arr[1] = '\0';
Note that this isn't the same as assigning NULL, since arr[1] is a char and not a pointer, you can't assign NULL to it.
That said, that probably won't do what you think it will. The above example will produce the string f, not fo as you seem to expect.
If you want to remove characters from a string, you have to shift the contents of the string to the left (including the null terminator) using memmove and some pointer arithmetic:
Example:
#include <stdio.h>
#include <string.h>
int removechars(char *str, size_t pos, size_t cnt) {
size_t len = strlen(str);
if (pos + cnt > len)
return -1;
memmove(str + pos, str + pos + cnt, len - pos - cnt + 1);
return 0;
}
Then use it like so:
char str[12] = "hello world";
if (removechars(str, 5, 4) == 0) /* remove 4 chars starting at str[5] */
printf("%s\n", str); /* hellold */
If you're talking about an array of pointers (say char **), you'd just say array[element] = NULL;. But it sounds as though you really want to just truncate a string (char *), in which case you'd actually want to write string[index] = '\0', where \0 is the null byte. But, as far as I know, 0, '\0', and NULL are all equivalent and equal to 0 (please correct me if I'm wrong). Of course, for clarity, you should use 0 for numbers, '\0' for chars and strings, and NULL for pointers.
Related
i wrote this code without looking on the net and having a look in the builtin.
how can remove that temp variable and write directly in one of the variable passed in strcat12()?
#include <stdio.h>
char temp[]="";
int strlen12(char *str) {
int count = 0;
while(*str) {
count++;
str++;
}
return count;
}
char strcat12(char *str, char *str2) {
int i = 0;
int l = strlen12(str);
while(*str) {
temp[i++] = *str;
str++;
}
while(*str2) {
temp[l++] = *str2;
str2++;
}
}
The code has some errors and some place on which it can comply with standard.
strlen function returns the length of the string. Better would be if you return size_t and parameter is of type const char*.
Now strcat doesn't behave the way you implemented it. What happens then? Standard says
char *strcat(char * restrict s1, const char * restrict s2);
The strcat function appends a copy of the string pointed to by s2 (including the terminating null character) to the end of the string pointed to by s1. The initial character of s2 overwrites the null character at the end of s1. If copying takes place between objects that overlap, the behavior is undefined.
Returns
The strcat function returns the value of s1.
char * mystrcat(char *dest, const char *src)
{
size_t i=0,j=0;
while( dest[i] ) i++ ;
while( src[j] ) { dest[i+j] = src[j]; j++; }
dest[i+j] = '\0';
return dest;
}
The same way strlen() returns size_t.
size_t strlen(const char *s){
size_t len = 0;
for( ; s[len] ; len++ )
;
return len;
}
Now the problems in your code
char temp[]="" this is an one length string containing only the single character \0.
This is not a good idea to have a function that will fill one of the char array when called with 2 strings. This side effect is not desirable and it is not reusable.
char strcat12(char *str, char *str2) You are supposed to return a char but you returned nothing.
char strcat12(char *str, char *str2) Again why do you want to return a char?
Now if you are using a global variable why do you even need to return anything as far as the code is given. void strcat12(char *str, char *str2) will be ok.
A slightly better idea can be that you will return a char* which will contain the concatenated string. What I mean by this is you will allocate memory and return pointer to that memory and the memory holds concatenated string.
regarding your question: how can remove that temp variable and write directly in one of the variable passed in strcat12()?
to write directly into the parameter 'str', the array pointed to by 'str' must be long enough to hold the contents of both parameters + the terminating NUL byte.
Then the variable temp[] does not need to be referenced.
here is one way to implement the strcat12() function:
char * strcat12(char *dest, const char *src)
{
size_t i;
for (i = 0; dest[i]; i++);
for (size_t j = 0; src[j]; j++)
dest[i+j] = src[j];
dest[i+j] = '\0';
return dest;
}
char * removeChar(char * str, char c){
int len = strlen(str);
int i = 0;
int j = 0;
char * copy = malloc(sizeof(char) * (len + 1));
while(i < len){
if(str[i] != c){
copy[j] = str[i];
j++;
i++;
}else{
i++;
}
}
if(strcmp(copy, str) != 0){
strcpy(str,copy);
}else{
printf("Error");
}
return copy;
}
int main(int argc, char * argv[]){
char str[] = "Input string";
char * input;
input = removeChar(str,'g');
printf("%s\n", input);
free(input);
return 0;
}
I don't know why every time I try to run it ,it always says uninitialized variable and sticks in the strcpy line and printf line.
Basically this function is to take a string, and a character and removes the that character from the string (because I am learning malloc so that's why I wrote the function like this).
After the while loop do:
copy[j] = '\0';
to NULL-terminate your string; that way it can work with methods coming from <string.h>, which assume that the string is nul-terminated.
PS: One warning you should see is about not returning copy in your function in any case, because now if the condition of the if statement is wrong, your function won't return something valid, so add this:
return copy;
at the end of your function (which is now corrected with your edit).
Other than that, the only warning you should still get are for the unused arguments of main(), nothing else:
prog.c: In function 'main':
prog.c:32:14: warning: unused parameter 'argc' [-Wunused-parameter]
int main(int argc, char * argv[]){
^~~~
prog.c:32:27: warning: unused parameter 'argv' [-Wunused-parameter]
int main(int argc, char * argv[]){
^~~~
While you copy over bytes from str to copy, you don't add a terminating null byte at the end. As a result, strcmp reads past the copied characters into unitialized memory, possibly past the end of the allocated memory block. This invokes undefined behavior.
After your while loop, add a terminating null byte to copy.
Also, you never return a value if the if block at the end is false. You need to return something for that, probably the copied string.
char * removeChar(char * str, char c){
int len = strlen(str);
int i = 0;
int j = 0;
char * copy = malloc(sizeof(char) * (len + 1));
while(i < len){
if(str[i] != c){
copy[j] = str[i];
j++;
i++;
}else{
i++;
}
}
// add terminating null byte
copy[j] = '\0';
if(strcmp(copy, str) != 0){
strcpy(str,copy);
}
// always return copy
return copy;
}
You never initialised input and the some compilers don't notice,
that the the value is never used before the line
input = removeChar(str, 'g');
in your code. So they emit the diagnostic just to be sure.
strcpy(str, copy)
gets stuck in your code, as copy never got a closing 0 byte and
so depends on the nondeterministic content of your memory at the
moment of the allocation of the memory backing copy, how long strcpy
will run and if you get eventually a SIGSEGV (or similar).
strcpy will loop until it finds a 0 byte in your memory.
For starters to remove a character from a string there is no need to create dynamically a character array and then copy this array into the original string.
Either you should write a function that indeed removes the specified character from a string or a function that creates a new string based on the source string excluding the specified character.
It is just a bad design that only confuses users. That is the function is too complicated and uses redundant functions like malloc, strlen, strcmp and strcpy. And in fact it has a side effect that is not obvious. Moreover there is used incorrect type int for the length of a string instead of the type size_t.
As for your function implementation then you forgot to append the terminating zero '\0' to the string built in the dynamically allocated array.
If you indeed want to remove a character from a string then the function can look as it is shown in the demonstrative program.
#include <stdio.h>
char * remove_char(char *s, char c)
{
char *p = s;
while (*p && *p != c) ++p;
for ( char *q = p; *p++; )
{
if (*p != c) *q++ = *p;
}
return s;
}
int main( void )
{
char str[] = "Input string";
puts(str);
puts(remove_char(str, 'g'));
return 0;
}
The program output is
Input string
Input strin
If you are learning the function malloc and want to use it you in any case should try to implement a correct design.
To use malloc you could write a function that creates a new string based on the source string excluding the specified character. For example
#include <stdio.h>
#include <stdlib.h>
char * remove_copy_char(const char *s, char c)
{
size_t n = 0;
for (const char *p = s; *p; ++p)
{
if (*p != c) ++n;
}
char *result = malloc(n + 1);
if (result)
{
char *q = result;
for (; *s; ++s)
{
if (*s != c) *q++ = *s;
}
*q = '\0';
}
return result;
}
int main( void )
{
char *str = "Input string";
puts(str);
char *p = remove_copy_char(str, 'g');
if ( p ) puts(p );
free(p);
return 0;
}
The program output will be the same as above.
Input string
Input strin
Pay attention to the function declaration
char * remove_copy_char(const char *s, char c);
^^^^^^
In this case the source string can be a string literal.
char *str = "Input string";
In C programming, suppose that I have some input strings with unknown length like:
abcde.xxx
abc.xxx
abcdefgh.xxx
....
How can I take the last 4 characters from them? I tried this way but it doesn't work:
char dest[] = "abcdef.ghi";
char s[5];
memset(s, '\n', sizeof s);
strncpy(s, dest - 5, 4);
But I can't use strstr() since the dest may be wrong with the format xxxx.xxx like abcd.xxxy
char s[5] = {0};
size_t len = 0;
char dest[] = "abcdef.ghi";
char *p = strchr(dest, '.');
if(!p)
{
// error no '.'
return;
}
len = strlen(p);
if(len != sizeof(s)-1)
{
// More or less than 3 characters plus '.'
return;
}
strcpy(s, p);
When the string is null-terminated you can use strlen to get the lenght of the string:
char s[5];
size_t len, offset;
char dest[] = "abcdef.ghi";
len = strlen(dest);
memset( s, '\0', sizeof(char)*5);
offset = len-4;
strncpy( s, &dest[offset], 4 );
If this is not the case you can loop over the string as an array and look for your dot.
Afterwards you can use this index to calculate your correct offset. But be careful for that solution. If one string does not hate a dt and last free character you can cause an access violation.
I'm stuck at yet another C problem. How can I concatenate two strings with the second string being inserted before the first string?
This is what I came up with. Unfortunately I'm stuck at all these pointer to chars, char arrays et cetera.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[] )
{
char* output;
int i;
for(i = 9; i > 0; i--)
{
unsigned int value = (unsigned int)i;
char buffer[20];
sprintf(buffer, "%u", value);
// strcat(ouput, buffer); // append before the string.
// first loop: 9
// second loop: 89
// third loop: 789
}
printf("%s", output);
}
How must I correct my code to make it work? I guess I have to somehow set the output variable to empty. When do I need fixed widths for the char array or the pointer? 20 was just a random guess from me.
I'm very confused, as your posted code has absolutely nothing to do with the problem you state. (Well, they both use strings, but that's about it)
char* src = "Hello, ";
char* dest = "World!";
char* temp;
temp = malloc(strlen(src) +strlen(dest) + 1);
strcpy(temp, src);
strcat(temp, dest);
dest = temp;
Unless dest is a fixed buffer of adequate size for the combined string. If so, then replace the last line with:
strcpy(dest, temp);
free(temp);
Now, if you want to specifically build the list of digits backwards, let's try a different tack:
char buffer[10];
buffer[9] = '\0'; // null terminate our string.
char* output;
int i;
for(i = 9; i > 0; i--)
{
// this is a fast way of saying, sprintf("%u", i);
// works only for single digits
char d = (char)('0' + i);
buffer[i-1] = d;
output = &buffer[i-1];
printf("%s", output);
}
Usually, you should just avoid the situation to start with. The most obvious solution for your example would be to simply count upward to start with. When that's not suitable, a recursive solution to reverse the order in which the string is built can still allow you to generate the string from beginning to end:
int build_string(int value, char *string) {
char temp[10];
if (value > -1)
build_string(value-1, string);
sprintf(temp, "%d", value); // use snprintf if available.
strcat(string, temp);
return string;
}
int main() {
char result[20] = {0};
build_string(9, result);
printf("%s", result);
return 0;
}
You can append the integer at the end of the string as:
int i;
char buffer[20];
for(i = 0; i < 10; i++) {
sprintf(buffer+i, "%u", i);
}
printf("%s", buffer); // prints 0123456789
For your stated problem (insert one string in front of another), this code will do the job - but has no error checking. It assumes there is enough space in the target buffer for the existing string and the new prefix:
/* Insert string t in front of string s in string s */
char *strinsert(char *s, const char *t)
{
char *p = s + strlen(s);
char *q = p + strlen(t);
char *r = s;
while (p >= s)
*q-- = *p--;
while (*t)
*s++ = *t++;
return(r);
}
What it does is copy the existing string up by the correct number of places so that there is space for the new string at the beginning.
Assuming that the destination buffer is big enough and that the source and destination do not overlap:
// not sure what order to put the params - the usual C way is destination
// followed by source, but it's also potentially confusing that the result of
// prepend(foo,bar) is "<bar><foo>".
char* prepend(char *restrict dest, const char *restrict src) {
size_t len = strlen(src);
memmove(dest + len, dest, strlen(dest));
return memcpy(dest, src, len);
}
If the buffers may overlap (for example, if src is the second half of dest), this approach doesn't work.
If the destination buffer is not big enough, then someone has to allocate new memory for the result, in which case the question of which is the "source" and which the "destination" disappears - they're both "source" and neither is "destination".
I have a C string that looks like "Nmy stringP", where N and P can be any character. How can I edit it into "my string" in C?
To "remove" the 1st character point to the second character:
char mystr[] = "Nmy stringP";
char *p = mystr;
p++; /* 'N' is not in `p` */
To remove the last character replace it with a '\0'.
p[strlen(p)-1] = 0; /* 'P' is not in `p` (and it isn't in `mystr` either) */
Another option, again assuming that "edit" means you want to modify in place:
void topntail(char *str) {
size_t len = strlen(str);
assert(len >= 2); // or whatever you want to do with short strings
memmove(str, str+1, len-2);
str[len-2] = 0;
}
This modifies the string in place, without generating a new address as pmg's solution does. Not that there's anything wrong with pmg's answer, but in some cases it's not what you want.
Further to #pmg's answer, note that you can do both operations in one statement:
char mystr[] = "Nmy stringP";
char *p = mystr;
p++[strlen(p)-1] = 0;
This will likely work as expected but behavior is undefined in C standard.
The most efficient way:
//Note destroys the original string by removing it's last char
// Do not pass in a string literal.
char * getAllButFirstAndLast(char *input)
{
int len = strlen(input);
if(len > 0)
input++;//Go past the first char
if(len > 1)
input[len - 2] = '\0';//Replace the last char with a null termination
return input;
}
//...
//Call it like so
char str[512];
strcpy(str, "hello world");
char *pMod = getAllButFirstAndLast(str);
The safest way:
void getAllButFirstAndLast(const char *input, char *output)
{
int len = strlen(input);
if(len > 0)
strcpy(output, ++input);
if(len > 1)
output[len - 2] = '\0';
}
//...
//Call it like so
char mod[512];
getAllButFirstAndLast("hello world", mod);
The second way is less efficient but it is safer because you can pass in string literals into input. You could also use strdup for the second way if you didn't want to implement it yourself.