Remove characters from a string in C [duplicate] - c

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Remove characters from a string in C
I'm creating a small todo application in C and I'd like to remove * then a space from a string I'm looping over each line then checking if the lineNumber is the one passed in to the function then I'd wondering how to remove the characters from that line, Heres the code where I loop over the lines
while (fgets(line, sizeof line, oldTodoFile)) {
len = strlen(line);
if (len && (line[len - 1] != '\n')) {} else {
lineNumber++;
if (lineNumber == todoNumber) {
// remove *[space]
} else {
fprintf(todoFile);
}
}

Sounds like you're asking how to remove a leading '* ' from the beginning of a string. You have two options:
You can either just move each character two spaces back, something like:
if(startsWithStarSpace) {
int i;
for(i = 2; i < len; ++i)
str[i-2] = str[i];
str[i] = '\0';
}
Or if your string is dynamically allocated, you can just move the pointer forward by two characters (making sure to save your old pointer to free() later).

a simple way to do this (note i know this is not the best way, i'm sure there is lots of standard functions for this) would be:
if(lineNumber == todoNumber) {
char buff[len];
char* bptr = buff;
char* lptr = line;
for(;lptr!=NULL;) {
if(*lptr!='*')
*bptr++ = *lptr++
else{
lptr++;lptr++; /*skip over * and space */
}
}
strcpy(line,buff); /* replace line with updated version */
}
Like I said, not the best solution but its one way to do it.

Related

Cannot assign chars from one string to another

So I have a function that takes a string, and strips out special format characters, and assigns it to another string for later processing.
A sample call would be:
act_new("$t does $d");
It should strip out the $t and the $d and leave the second string as " does ", but its not assigning anything. I am getting back into programming after quite a few years of inactivity, and this is someone elses code (A MUD codebase, Rom), but I feel like I am missing something fundamental with pointer assignments. Any tips?
(This is truncated code, the rest has no operations on str or point until much later)
void act_new(const char *format)
{
const char *str;
char *point;
str = format;
while ( *str != '\0' ) {
if ( *str != '$' ) {
*point++ = *str++;
continue;
}
}
}
You need to increment str every time through the loop, not only when you assign to point. Otherwise you end up in an infinite loop when the character doesn't match the if condition.
You also want to skip the character after $, so you have to increment str twice when you encounter $.
The code is simpler if you use a for loop and array indexing rather than pointer arithmetic.
size_t len = strlen(format);
for (size_t i = 0; i < len; i++) {
if (format[i] == '$') {
i++; // extra increment to skip character after $
} else {
*point++ = format[i];
}
}
There are a few problems with your code, as pointed out in the comments:
point is not initialized (garbage pointer value)
continue doesn't do anything
infinite loop if a $ is encountered
When writing the function, one must also keep in mind to skip an extra character if a $ is encountered if and only if it's not the last character in the string (except for the '\0').
Since you know how many times you need to loop, a for loop is better suited and, as a bonus, you don't have to explicitly check if the character after a $ is '\0' when skipping an extra character in format (renamed src below). Also, don't forget to terminate the destination string.
This code will take care of those things for you:
void act_new(const char *src)
{
const size_t length = strlen(src);
char * const dst = (char*)malloc(sizeof(char)*(length+1));
if(dst == NULL)
// Error handling left out
return;
char *point = dst;
for(size_t i = 0; i < length; ++i)
{
if(src[i] == '$')
{
++i;
continue;
}
*point++ = src[i];
}
*point = '\0'; //Terminate string properly
printf("%s\n", dst);
free(dst);
}

How to reuse strings in C without old values showing up in the memory?

I'm sure this is extremely simple and probably gets asked a lot but this is driving me absolutely crazy and I cant even figure out how to properly word my question to search for an answer.
Basically, I'm reading a txt file (in C) and identifying how many times a word appears.
I grab an entire line from the txt file using getLine();
copy every character to a string until I reach a space
Sends the new string to another function that parses out invalid characters
The problem I'm running into is each time it goes through the loop, it keeps the old characters in the string and just replaces them. I'm trying to set this up so after a word is passed to parseWord, that temporary string named newWord is reset (and empty). Likewise, cleanWord in the parseWord function is doing the same thing.
I'm sure there is an easy solution to this, but I just don't understand how to and its becoming extremely frustrating. Any help would be very appreciated.
void readFiles(FILE *file1, List *theList, int fileNum) {
int i, lineIndex;
char *newLine;
size_t lineLength = 0;
while(lineLength=getline(&newLine, &lineLength, file1)>0){
lineIndex = 0;
i = 0;
char *newWord;//saves individual words
while(newLine[lineIndex] != '\0'){ //move to new space
if(newLine[lineIndex] == ' '){
//insert(&theList, parseWord(i, newWord), fileNum);
parseWord(i, newWord);
i = 0;
}else{
newWord[i] = newLine[lineIndex];
i++;
}
lineIndex++;
}
}
}
char *parseWord(int theLen, char *theWord){
char cleanWord[theLen]; //the word without other stuff
char *finalWord;
int i, j;
for(j = i = 0; i < theLen; i++) {
char tmp = theWord[i];
if (tmp >= 'A' && tmp <= 'Z') {
cleanWord[j] = tolower((unsigned char) theWord[i]);
j++;
} else if ((tmp >= 'a' && tmp <= 'z') || tmp == 39 || tmp == 45) {
cleanWord[j] = theWord[i];
j++;
}
}
return strcpy(finalWord, cleanWord);
}
For example: the first line being read is: The Red Badge of Courage
when the word gets passed into the second fuction, for theWord I get:
The
Red
Badge
ofdge (this should be of)
A lot of good answers in the comments all of which helped me solve my problem.
I started adding a null terminating character to the end of each string copy which helped eliminate unnecessary characters.
I still don't quite understand the proper method for reusing strings but for all intents and purposes, my problem was solved. Thanks everyone.
Note: Part of my problem was I was trying to reset each string by using
cleanWord = '\0';
which was causing a segfault the next time it tried to assign a char to it.

Reverse the words in a String [duplicate]

This question already has answers here:
Reverse the ordering of words in a string
(48 answers)
Closed 8 years ago.
I need a program to reverse the words in a string.
Input: My car is fast
Output: fast is car My
int printRword(char * line) {
for(; *line; line++) {
if(*line == ' ') {
printRword(line + 1);
printf("%s", line);
return 0; // after you find the space set it to null
}
}
}
int main(void) {
char *line = "this is a long line that we are working with\n";
printf("%s", line);
printRword(line);
return 0;
}
I know I need to set space to null after I find it, and I've tried printRword(line + 1) = '\0';
and that doesn't work
any suggestions?
You could reverse the whole string, and then reverse each individual word, having the effect of reversing the order of the words but leaving the letters in each word in the correct order. Not the most efficient, perhaps, but conceptually clean -- and not language dependent!
Find the modified working code:
int printRword(char * line)
{
char tempbuf[100]; //Here length i have hardcoded to 100
char *ptr;
strcpy(tempbuf,line); //copied to tempbuf to keep the original string unmodified
//Replace the \n with the null character
ptr = strrchr(tempbuf,'\n');
if(ptr != NULL)
{
*ptr = '\0';
}
while(*tempbuf != '\0')
{
ptr = strrchr(tempbuf,' ');
if(NULL != ptr)
{
*ptr = '\0';
ptr++;
printf("%s ",ptr);
}
else
{
printf("%s\n",tempbuf);
*tempbuf ='\0';
}
}
}
test result:
atharv#atharv-Inspiron-5423:~/Programming$ ./a.out
this is a long line that we are working with
with working are we that line long a is this
atharv#atharv-Inspiron-5423:~/Programming$
You could go through the string character-by-character, replacing the spaces by ASCII NUL characters (C's string terminators), and recording the next position in each case (by pushing onto a stack), thus recording the beginning of each word. When you get to the end of the string, you can then go backwards through the list of “start-of-word” positions (perhaps by popping off the stack), printing out the word each time followed by a space.
This is the basic idea. If you have to handle multiple spaces between words or newlines, it gets a little bit more complicated, but not much.
I modified your code using the same recursive approach to get the desired output, just added a function that would print only till next space.. there must be a function for this already but i am not aware of it.
#include <stdio.h>
void printTillNextSpace(char *s){
while(*s != ' ' && *s != '\0' && *s != '\n')
printf("%c",*s++);
printf("%c",' ');
}
int printRword(char * line){
char* start = line;
for(;*line; line++){
if(*line == ' '){
printRword(line + 1);
printTillNextSpace(start);
start = line + 1;
return 0; // after you find the space set it to null
}
}
printTillNextSpace(start);
}
int main(){
char * line = "this is a long line that we are working with\n";
printf("%s", line);
printRword(line);
return 0;
}

How does C know the end of my string?

I have a program in which I wanted to remove the spaces from a string. I wanted to find an elegant way to do so, so I found the following (I've changed it a little so it could be better readable) code in a forum:
char* line_remove_spaces (char* line)
{
char *non_spaced = line;
int i;
int j = 0;
for (i = 0; i <= strlen(line); i++)
{
if ( line[i] != ' ' )
{
non_spaced[j] = line[i];
j++;
}
}
return non_spaced;
}
As you can see, the function takes a string and, using the same allocated memory space, selects only the non-spaced characters. It works!
Anyway, according to Wikipedia, a string in C is a "Null-terminated string". I always thought this way and everything was good. But the problem is: we put no "null-character" in the end of the non_spaced string. And somehow the compiler knows that it ends at the last character changed by the "non_spaced" string. How does it know?
This does not happen by magic. You have in your code:
for (i = 0; i <= strlen(line); i++)
^^
The loop index i runs till strlen(line) and at this index there is a nul character in the character array and this gets copied as well. As a result your end result has nul character at the desired index.
If you had
for (i = 0; i < strlen(line); i++)
^^
then you had to put the nul character manually as:
for (i = 0; i < strlen(line); i++)
{
if ( line[i] != ' ' )
{
non_spaced[j] = line[i];
j++;
}
}
// put nul character
line[j] = 0;
Others have answered your question already, but here is a faster, and perhaps clearer version of the same code:
void line_remove_spaces (char* line)
{
char* non_spaced = line;
while(*line != '\0')
{
if(*line != ' ')
{
*non_spaced = *line;
non_spaced++;
}
line++;
}
*non_spaced = '\0';
}
The loop uses <= strlen so you will copy the null terminator as well (which is at i == strlen(line)).
You could try it. Debug it while it is processing a string containing only one space: " ". Watch carefully what happens to the index i.
How do you know that it "knows"? The most likely scenario is that you're simply having luck with your undefined behavior, and that there is a '\0'-character after the valid bytes of line end.
It's also highly likely that you're not seeing spaces at the end, which might be printed before hitting the stray "lucky '\0'".
A few other points:
There's no need to write this using indexing.
It's not very efficient to call strlen() on each loop iteration.
You might want to use isspace() to remove more whitespace characters.
Here's how I would write it, using isspace() and pointers:
char * remove_spaces(char *str)
{
char *ret = str, *put = str;
for(; *str != '\0'; str++)
{
if(!isspace((unsigned char) *str)
*put++ = *str;
}
*put = '\0';
return ret;
}
Note that this does terminate the space-less version of the string, so the returned pointer is guaranteed to point at a valid string.
The string parameter of your function is null-terminated, right?
And in the loop, the null character of the original string get also copied into the non spaced returned string. So the non spaced string is actually also null-terminated!
For your compiler, the null character is just another binary data that doesn't get any special treatment, but it's used by string APIs as a handy character to easily detect end of strings.
If you use the <= strlen(line), the length of the strlen(line) include the '\0' so your program can work. You can use debug and run analysis.

Scanning in more than one word in C

I am trying to make a program which needs scans in more than one word, and I do not know how to do this with an unspecified length.
My first port of call was scanf, however this only scans in one word (I know you can do scanf("%d %s",temp,temporary);, but I do not know how many words it needs), so I looked around and found fgets. One issue with this is I cannot find how to make it move to the next code, eg
scanf("%99s",temp);
printf("\n%s",temp);
if (strcmp(temp,"edit") == 0) {
editloader();
}
would run editloader(), while:
fgets(temp,99,stdin);
while(fgets(temporary,sizeof(temporary),stdin))
{
sprintf(temp,"%s\n%s",temp,temporary);
}
if (strcmp(temp,"Hi There")==0) {
editloader();
}
will not move onto the strcmp() code, and will stick on the original loop. What should I do instead?
I would scan in each loop a word with scanf() and then copy it with strcpy() in the "main" string.
maybe you can use getline method ....I have used it in vc++ but if it exists in standard c library too then you are good to go
check here http://www.daniweb.com/software-development/c/threads/253585
http://www.cplusplus.com/reference/iostream/istream/getline/
Hope you find what you are looking for
I use this to read from stdin and get the same format that you would get by passing as arguments... so that you can have spaces in words and quoted words within a string. If you want to read from a specific file, just fopen it and change the fgets line.
#include <stdio.h>
void getargcargvfromstdin(){
char s[255], **av = (char **)malloc(255 * sizeof(char *));
unsigned char i, pos, ac;
for(i = 0; i < 255; i++)
av[i] = (char *)malloc(255 * sizeof(char));
enum quotes_t{QUOTED=0,UNQUOTED}quotes=UNQUOTED;
while (fgets(s,255,stdin)){
i=0;pos=0;ac=0;
while (i<strlen(s)) {
/* '!'=33, 'ÿ'=-1, '¡'=-95 outside of these are non-printables */
if ( quotes && ((s[i] < 33) && (s[i] > -1) || (s[i] < -95))){
av[ac][pos] = '\0';
if (av[ac][0] != '\0') ac++;
pos = 0;
}else{
if (s[i]=='"'){ /* support quoted strings */
if (pos==0){
quotes=QUOTED;
}else{ /* support \" within strings */
if (s[i-1]=='\\'){
av[ac][pos-1] = '"';
}else{ /* end of quoted string */
quotes=UNQUOTED;
}
}
}else{ /* printable ascii characters */
av[ac][pos] = s[i];
pos++;
}
}
i++;
}
//your code here ac is the number of words and av is the array of words
}
}
If it exceeds the buffer size you simply can't do it.
You will have to do multiple loops
the maximum size you can scan with scanf() will come from
char *name;
scanf("%s",name);
reed this
http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html

Resources