Removing last character in C - c

The program I am writing needs to remove an ampersand character if it is the last character of a string. For instance, if char* str contains "firefox&", then I need to remove the ampersand so that str contains "firefox". Does anyone know how to do this?

Just set the last char to be '\0':
str[strlen(str)-1] = '\0';
In C, \0 indicates a string ending.

Every string in C ends with '\0'. So you need do this:
int size = strlen(my_str); //Total size of string
my_str[size-1] = '\0';
This way, you remove the last char.

To be on the safe side:
if (str != NULL)
{
const unsigned int length = strlen(str);
if ((length > 0) && (str[length-1] == '&')) str[length-1] = '\0';
}

Just for reference, the standard function strchr does just that. It effectively splits the string on a given set of characters. It works by substituting a character with 0x00
Example shamelessly stolen from: cplusplus.com
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "This is a firefox& string";
char * pch;
printf ("Looking for the '&' character in \"%s\"...\n",str);
pch=strchr(str,'&');
while (pch!=NULL)
{
printf ("found at %d\n",pch-str+1);
pch=strchr(pch+1,'&');
}
return 0;
}

Check the last character and if it is '&', replace it with '\0' (null terminator):
int size = strlen(my_str);
if (str[size - 1] == '&')
str[size - 1] = '\0';

Related

Trim function in C

I am writing my own trim() in C. There is a structure which contains all string values, the structure is getting populated from the data coming from a file which contains spaces before and after the beginning of a word.
char *trim(char *string)
{
int stPos,endPos;
int len=strlen(string);
for(stPos=0;stPos<len && string[stPos]==' ';++stPos);
for(endPos=len-1;endPos>=0 && string[endPos]==' ';--endPos);
char *trimmedStr = (char*)malloc(len*sizeof(char));
strncpy(trimmedStr,string+stPos,endPos+1);
return trimmedStr;
}
int main()
{
char string1[]=" a sdf ie ";
char *string =trim(string1);
printf("%s",string);
return 0;
}
Above code is working fine, but i don't want to declare new variable that stores the trimmed word. As the structure contains around 100 variables.
Is there any way to do somthing like below where I dont need any second variable to print the trimmed string.
printf("%s",trim(string1));
I believe above print can create dangling pointer situation.
Also, is there any way where I don't have to charge original string as well, like if I print trim(string) it will print trimmed string and when i print only string, it will print original string
elcuco was faster. but it's done so here we go:
char *trim(char *string)
{
char *ptr = NULL;
while (*string == ' ') string++; // chomp away space at the start
ptr = string + strlen(string) - 1; // jump to the last char (-1 because '\0')
while (*ptr == ' '){ *ptr = '\0' ; ptr--; } ; // overwrite with end of string
return string; // return pointer to the modified start
}
If you don't want to alter the original string I'd write a special print instead:
void trim_print(char *string)
{
char *ptr = NULL;
while (*string == ' ') string++; // chomp away space at the start
ptr = string + strlen(string) - 1; // jump to the last char (-1 because '\0')
while (*ptr == ' '){ ptr--; } ; // find end of string
while (string <= ptr) { putchar(*string++); } // you get the picture
}
something like that.
You could the original string in order to do this. For trimming the prefix I just advance the pointer, and for the suffix, I actually add \0. If you want to keep the original starting as is, you will have to move memory (which makes this an O(n^2) time complexity solution, from an O(n) I provided).
#include <stdio.h>
char *trim(char *string)
{
// trim prefix
while ((*string) == ' ' ) {
string ++;
}
// find end of original string
char *c = string;
while (*c) {
c ++;
}
c--;
// trim suffix
while ((*c) == ' ' ) {
*c = '\0';
c--;
}
return string;
}
int main()
{
char string1[] = " abcdefg abcdf ";
char *string = trim(string1);
printf("String is [%s]\n",string);
return 0;
}
(re-thinking... is it really O(n^2)? Or is it O(2n) which is a higher O(n)...? I guess depending on implementation)
You can modify the function by giving the output in the same input string
void trim(char *string)
{
int i;
int stPos,endPos;
int len=strlen(string);
for(stPos=0;stPos<len && string[stPos]==' ';++stPos);
for(endPos=len-1;endPos>=0 && string[endPos]==' ';--endPos);
for (i=0; i<=(endPos-stPos); i++)
{
string[i] = string[i+stPos];
}
string[i] = '\0'; // terminate the string and discard the remaining spaces.
}
...is there any way where i don't have to charge original string as well, like if i do trim(string) it will print trimmed string and when i print only string, it will print original string – avinashse 8 mins ago
Yes, though it gets silly.
You could modify the original string.
trim(string);
printf("trimmed: %s\n", string);
The advantage is you have the option of duplicating the string if you want to retain the original.
char *original = strdup(string);
trim(string);
printf("trimmed: %s\n", string);
If you don't want to modify the original string, that means you need to allocate memory for the modified string. That memory then must be freed. That means a new variable to hold the pointer so you can free it.
char *trimmed = trim(original);
printf("trimmed: %s\n", trimmed);
free(trimmed);
You can get around this by passing a function pointer into trim and having trim manage all the memory for you.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void trim(char *string, void(*func)(char *) )
{
// Advance the pointer to the first non-space char
while( *string == ' ' ) {
string++;
}
// Shrink the length to the last non-space char.
size_t len = strlen(string);
while(string[len-1]==' ') {
len--;
}
// Copy the string to stack memory
char trimmedStr[len + 1];
strncpy(trimmedStr,string, len);
// strncpy does not add a null byte, add it ourselves.
trimmedStr[len] = '\0';
// pass the trimmed string into the user function.
func(trimmedStr);
}
void print_string(char *str) {
printf("'%s'\n", str);
}
int main()
{
char string[]=" a sdf ie ";
trim(string, print_string);
printf("original: '%s'\n", string);
return 0;
}
Ta da! One variable, the original is left unmodified, no memory leaks.
While function pointers have their uses, this is a bit silly.
It's C. Get used to managing memory. ¯\_(ツ)_/¯
Also, is there any way where I don't have to charge original string as
well, like if I print trim(string) it will print trimmed string and
when i print only string, it will print original string
Yes you can, but you cannot allocate new memory in the trim function as you will not be holding the return memory.
You can have a static char buffer in the trim function and operate on it.
Updated version of #elcuco answer.
#include <stdio.h>
char *trim(char *string)
{
static char buff[some max length];
// trim prefix
while ((*string) == ' ' ) {
string++;
}
// find end of original string
int i = 0;
while (*string) {
buff[i++] = *string;
string++;
}
// trim suffix
while ((buff[i]) == ' ' ) {
buff[i] = '\0';
i--;
}
return buff;
}
int main()
{
char string1[] = " abcdefg abcdf ";
char *string = trim(string1);
printf("String is [%s]\n",string);
return 0;
}
With this you don't need to worry about holding reference to trim function return.
Note: Previous values of buff will be overwritten with new call to trim function.
If you don't want to change the original, then you will need to make a copy, or pass a second array of sufficient size as a parameter to your function for filling. Otherwise a simple in-place trmming is fine -- so long as the original string is mutable.
An easy way to approach trimming on leading and trailing whitespace is to determine the number of leading whitespace characters to remove. Then simply use memmove to move from the first non-whitespace character back to the beginning of the string (don't forget to move the nul-character with the right portion of the string).
That leaves only removing trailing whitespace. An easy approach there is to loop from the end of the string toward the beginning, overwriting each character of trailing whitespace with a nul-character until your first non-whitespace character denoting the new end of string is found.
A simple implementation for that could be:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define DELIM " \t\n" /* whitespace constant delimiters for strspn */
/** trim leading and trailing whitespace from s, (s must be mutable) */
char *trim (char *s)
{
size_t beg = strspn (s, DELIM), /* no of chars of leading whitespace */
len = strlen (s); /* length of s */
if (beg == len) { /* string is all whitespace */
*s = 0; /* make s the empty-string */
return s;
}
memmove (s, s + beg, len - beg + 1); /* shift string to beginning */
for (int i = (int)(len - beg - 1); i >= 0; i--) { /* loop from end */
if (isspace(s[i])) /* checking if char is whitespace */
s[i] = 0; /* overwrite with nul-character */
else
break; /* otherwise - done */
}
return s; /* Return s */
}
int main (void) {
char string1[] = " a sdf ie ";
printf ("original: '%s'\n", string1);
printf ("trimmed : '%s'\n", trim(string1));
}
(note: additional intervening whitespace was added to your initial string to show that multiple intervening whitespace is left unchanged, the output is single-quoted to show the remaining text boundaries)
Example Use/Output
$ ./bin/strtrim
original: ' a sdf ie '
trimmed : 'a sdf ie'
Look things over and let me know if you have further questions.

Printing a string due to a new line

Is there any efficient (- in terms of performance) way for printing some arbitrary string, but only until the first new line character in it (excluding the new line character) ?
Example:
char *string = "Hello\nWorld\n";
printf(foo(string + 6));
Output:
World
If you are concerned about performance this might help (untested code):
void MyPrint(const char *str)
{
int len = strlen(str) + 1;
char *temp = alloca(len);
int i;
for (i = 0; i < len; i++)
{
char ch = str[i];
if (ch == '\n')
break;
temp[i] = ch;
}
temp[i] = 0;
puts(temp);
}
strlen is fast, alloca is fast, copying the string up to the first \n is fast, puts is faster than printf but is is most likely far slower than all three operations mentioned before together.
size_t writetodelim(char const *in, int delim)
{
char *end = strchr(in, delim);
if (!end)
return 0;
return fwrite(in, 1, end - in, stdout);
}
This can be generalized somewhat (pass the FILE* to the function), but it's already flexible enough to terminate the output on any chosen delimiter, including '\n'.
Warning: Do not use printf without format specifier to print a variable string (or from a variable pointer). Use puts instead or "%s", string.
C strings are terminated by '\0' (NUL), not by newline. So, the functions print until the NUL terminator.
You can, however, use your own loop with putchar. If that is any performance penalty is to be tested. Normally printf does much the same in the library and might be even slower, as it has to care for more additional constraints, so your own loop might very well be even faster.
for ( char *sp = string + 6 ; *sp != '\0'; sp++ ) {
if ( *sp == '\n' ) break; // newline will not be printed
putchar(*sp);
}
(Move the if-line to the end of the loop if you want newline to be printed.)
An alternative would be to limit the length of the string to print, but that would require finding the next newline before calling printf.
I don't know if it is fast enough, but there is a way to build a string containing the source string up to a new line character only involving one standard function.
char *string = "Hello\nWorld\nI love C"; // Example of your string
static char newstr [256]; // String large enough to contain the result string, fulled with \0s or NULL-terimated
sscanf(string + 6, "%s", newstr); // sscanf will ignore whitespaces
sprintf(newstr); // printing the string
I guess there is no more efficient way than simply looping over your string until you find the first \n in it. As Olaf mentioned it, a string in C ends with a terminating \0 so if you want to use printf to print the string you need to make sure it contains the terminating \0 or yu could use putchar to print the string character by character.
If you want to provide a function creating a string up to the first found new line you could do something like that:
#include <stdio.h>
#include <string.h>
#define MAX 256
void foo(const char* string, char *ret)
{
int len = (strlen(string) < MAX) ? (int) strlen(string) : MAX;
int i = 0;
for (i = 0; i < len - 1; i++)
{
if (string[i] == '\n') break;
ret[i] = string[i];
}
ret[i + 1] = '\0';
}
int main()
{
const char* string = "Hello\nWorld\n";
char ret[MAX];
foo(string, ret);
printf("%s\n", ret);
foo(string+6, ret);
printf("%s\n", ret);
}
This will print
Hello
World
Another fast way (if the new line character is truly unwanted)
Simply:
*strchr(string, '\n') = '\0';

How to know if a char array has a null element in C?

Say if I have :
unsigned char* str = "k0kg"
And 0 is the null element. When I loop through it using a for loop, how do I check if the array has a null?
I tried:
if (str[1]==0):
I also tried:
if (str[1]=="0"):
And they didn't work. :(
The loop:
for (i=0;i<num_bytes;i++){
if (str[i]!=0){
printf("null spotted\n");
}
In C, strings, by definition, are terminated by '\0', the NUL character. So all (valid) strings have a '\0' in them, at the end.
To find the position of the '\0', simply use strlen():
const char * const end = str + strlen(str);
It's odd that you are using "unsigned char" if you are dealing with normal, printable strings. If you mean that you have a memory block with bytes it in and you want to find the first 0x00 byte, then you'll need a pointer to the start of the memory and the size of the memory area, in bytes. Then, you'd use memchr():
// Where strSize is the number of bytes that str points to.
const unsigned char * const end = memchr(str, 0, strSize);
If you are actually looking for the null element then you should do the following condition :
if(str[i]=='\0')
Say if I have : unsigned char* str = "k0kg"
And 0 is the null element. When I loop through it using a for loop, how do I check if the array has a null?
You're terminology is going to confuse any C programmer. You're confusing character representations with values. You're not looking for a null character ("null element", which would be '\0'), you're looking for the character '0'. So...
int len = strlen(str);
for(int i = 0; i < len; ++i) {
if(str[i] == '0')
printf("found it");
}
use strchr
#include <stdio.h>
#include <string.h>
int main(){
char *str = "k0kg";
char *p = strchr(str, '0');
if(p){
printf("find at %d\n", (int)(p - str));//find at 1
}
if(p=strchr(str, 0)){
printf("find at %d\n", (int)(p - str));//find at 4
}
str = "k\0kg";
if(p=strchr(str, 0)){
printf("find at %d\n", (int)(p - str));//find at 1
}
return 0;
}

What is wrong with this code?

As you can see below I have created a little program to concatenate 2 strings using C, as you may imagine this code doesn't work, I have already corrected it myself by using Array notation instead of pointers, and it works just fine, however I'm still not sure why is it that my code fails being almost a replica of my corrected code.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void concatena(char *str1, char *str2){
char *strAux;
int mover;
mover = 0;
strAux = (char *)(malloc(strlen(str1) + strlen(str2)+2));
*(strAux) = '\0';
if(str1 == '\0')
*strAux = '\0';
else
while(str1 != '\0'){
*(strAux+mover++)=*(str1++);
}
if(str2 == '\0')
*strAux = '\0';
else
while(str2 != '\0'){
*(strAux+mover++)=*(str2++);
}
strAux='\0';
str1=strAux;
printf("%s", str1);
free(strAux);
}
I´m still a C beginner (And yes, I'm aware that there are libraries like string.h, I'm asking this for academic reasons) and I have been told that char pointers and arrays are the same thing, something that confuses the heck out of me.
Any help is greatly appreciated.
The first problem I see is with this section:
if(str2 == '\0')
*strAux = '\0';
Just before this code, you've filled up strAux with the string from str1.
Then, if str2 is empty, you suddenly put a null-terminator at the beginning of strAux, eliminating all the work you've done so far!
I think what you intend is:
if(*str2 == '\0')
*(strAux+mover) = '\0';
Its the same thing again after your loop for str2, you have the code:
strAux='\0';
Again, this puts a null-terminator at the start of strAux, effectively ending the newly created string before it even gets started.
Here's how I'd re-write your code:
void concatena(char *str1, char *str2){
char *strAux;
int mover = 0;
strAux = (char *)(malloc(strlen(str1) + strlen(str2)+1)); // Changed to +1, NOT +2
*(strAux) = '\0'; // Start the string as (empty)
while(*str1 != '\0'){ // Copy the first string over.
*(strAux+mover++)=*(str1++);
}
while(*str2 != '\0'){ // Copy the second string over.
*(strAux+mover++)=*(str2++);
}
*(strAux+mover)='\0'; // End the new, combined string.
printf("%s", strAux); // Show the results.
free(strAux);
}
Accepting the same constraints, here is how I would (re)write your code. Unfortunately there is a specification shortcoming: should the concatenation occur to the first string passed? Or should a new string be created? Here are both methods:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
char *concatena (const char *str1, const char *str2)
{
char *op, *newStr = (char*)malloc (strlen (str1) + strlen (str2) + 1);
if (!newStr)
{
fprintf (stderr, "concatena: error allocating\n");
return;
}
op = newStr; // set up output pointer
while (str1 && *str1) // copy first string
*op++ = *str1++;
while (str2 && *str2) // concatenate second string
*op++ = *str2++;
*op = '\000'; // add conventional NUL termination
return newStr;
}
void concatenb (char *str1, const char *str2)
{
char *op;
if (!str1)
{
fprintf (stderr, "concatenb: NULL string 1\n");
return;
}
op = &str1 [strlen (str1)]; // set output pointer at trailing NUL
while (str2 && *str2) // concatenate second string
*op++ = *str2++;
*op = '\000'; // add conventional NUL termination
}
strAux = (char *)(malloc(strlen(str1) + strlen(str2)+2));
2 is not required, just 1 is sufficient for the termination character.
*(strAux) = '\0';
This should be happening only at the end of all your computation. Not in between the concatenation i.e.,
while(*str1 != '\0'){ // This loops copies the first string
// ^ Notice that you need to dereference to check for the termination character.
*(strAux+mover++)=*(str1++);
}
while(*str2 != '\0'){ // This loop copies the second string
*(strAux+mover++)=*(str2++);
}
// Finally adding termination character
*(strAux+mover) = '\0'; // since with mover you are keeping track of locations.
The amount of errors in your code is disheartening. You should probably pick up a good C book and start over.
First off, there's a library function that you can use to concatenate strings:
const unsigned int len = strlen(str1) + strlen(str2) + 1;
char * dst = malloc(len);
strncat(dst, str1, len);
strncat(dst, str2, len);
Now, if you insist on doing it manually, you have to get pointers and dereferencing right:
char * d = dst;
while (*str1 != 0) *dst++ = *str1++;
while (*str2 != 0) *dst++ = *str2++;
*dst = 0;
// d now points to the beginning of the concatenated string
The two loops check if the current character in the input string is nonzero, and if so, then they copy that character to the current character in the output string, and then both input and output pointer are advanced. (This is all done in one wash by use of the postfix ++ operator.) Finally, the last character is set to zero to create a new null-terminator.
In the process we modified all three pointers dst, str1 and str2. The latter two came in as input function arguments by copy, so that's fine. For returning the concatenated string we made a copy of dst before the loop, which we can return in the end.

How would I replace the character in this example using strchr?

/* strchr example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "This is a sample string";
char * pch;
printf ("Looking for the 's' character in \"%s\"...\n",str);
pch=strchr(str,'s');
while (pch!=NULL)
{
printf ("found at %d\n",pch-str+1);
pch=strchr(pch+1,'s');
}
return 0;
}
How would I index the str so that I would replace every 's' with 'r'.
Thanks.
You don't need to index the string. You have a pointer to the character you want to change, so assign via the pointer:
*pch = 'r';
In general, though, you index using []:
ptrdiff_t idx = pch - str;
assert(str[idx] == 's');
You can use the following function:
char *chngChar (char *str, char oldChar, char newChar) {
char *strPtr = str;
while ((strPtr = strchr (strPtr, oldChar)) != NULL)
*strPtr++ = newChar;
return str;
}
It simply runs through the string looking for the specific character and replaces it with the new character. Each time through (as with yours), it starts with the address one beyond the previous character so as to not recheck characters that have already been checked.
It also returns the address of the string, a trick often used so that you can use the return value as well, such as with:
printf ("%s\n", chngChar (myName, 'p', 'P'));
void reeplachar(char *buff, char old, char neo){
char *ptr;
for(;;){
ptr = strchr(buff, old);
if(ptr==NULL) break;
buff[(int)(ptr-buff)]=neo;
}
return;
}
Usage:
reeplachar(str,'s','r');
Provided that your program does really search the positions without fault (I didn't check), your question would be how do I change the contents of an object to which my pointer pch is already pointing?

Resources