I wrote a function to replace the blank spaces with tab character. But when I tried to implement it using function. I am quite not understanding how to call this function. I need functions
Which takes string from user as input,
Second function which replaces the blank space with tab character,
Function to print the modified string.
I achieved second one:
void SecondFunction()
{
char string[] = "I am new to c";
char *p = string;
for (; *p; ++p)
{
if (*p == ' ')
*p = '\t';
}
printf(string);
}
And when I tried to call this function like:
int main()
{
SecondFunction("Hi s");
}
By changing my function to:
void SecondFunction(char* str)
{
char string[] = str;
char *p = string;
....
...etc
}
I get the following error:
error: invalid initializer
char string[] = str;
^
Please, can anybody help me to write the 3 functions of my requirement?
Reading user input
To read input from the user you can use scanf. You need to pass it the memory address of the variable where you want to store the input:
char userinput[256]; // make it large enough to hold what the user inputs
scanf("%s", userinput); // array decays to pointer so no '&' here
The %s means were reading string input. We could also read an int using %d, like this:
int i;
scanf("%d", &i); // note the address-of operator '&' to get the address of i
Printing variables
Your SecondFunction is almost correct. To printf a C-string you need to use a syntax similar to when you scanf to a variable:
printf("%s", string);
Similarly, you could print the int i like this:
printf("The number is: %d", i);
Copying C-strings
When you tried doing this: char string[] = str, that's not possible. Arrays cannot be assigned or even copy constructed.
Just in case for the future, when you want to copy a C-string, you need to use strcpy:
char string[256]; // again, must be large enough to hold the new contents
strcpy(string, str); // copies from str to string
So in conclusion, your function could look something like this:
void SecondFunction(char* str)
{
char string[256];
strcpy(string, str);
char *p = string;
for (; *p; ++p)
{
if (*p == ' ')
*p = '\t';
}
printf("%s", string);
}
Bonus: Why you can't write to the str parameter directly
When you write this: SecondFunction("Hi s"), the string "Hi s" gets stored in a read-only memory segment.
If you then go and try to modify the parameter inside SecondFunction, you get undefined behavior, possibly a segmentation fault.
Related
I’m learning C, dealing with strings and pointers. An exercise calls for deleting all leading characters (‘X’ in this case) before a string. The called function must accept a string, i.e. a pointer to a char. I have found multiple ways of doing this by searching, but I do not understand why the following code does not work...what concept am I missing?
//delete all leading X characters by passing pointer to a string
#include <stdio.h>
#include <string.h>
void delChar(char* str)
{
char* walker; //declare pointer
walker = str; //point to beginning of passed string
while(*walker == 'X') walker++; //move pointer past amy leading 'X'
printf("\nwalker string is now: %s", walker); //prints "Test" as expected
str = walker; //set str pointer to walker
printf("\nstr string is now: %s", str); //prints "Test" as expected
return;
}
int main()
{
char* myStr = "XXXXXXXXXXXXTest";
printf("Before function call: %s", myStr); //prints "XXXXXXXXXXXXTest" as expected
delChar(myStr); //pass pointer to the string
printf("\nAfter function call: %s", myStr); //WHY DOES THIS print "XXXXXXXXXXXXTest" ?
return 0;
}
There are multiple ways in which characters can be deleted from a string, and it is not clear which you want.
In C, memory contents cannot be “deleted.” Memory is formed of bytes, and bytes hold values. When we have a string, it exists in a certain place in memory, and the bytes of the string cannot be made to go away.
Three ways to delete characters from a string are:
Given the start address of the string, return the address of the desired part of the string.
Given a pointer to the start of the string, update the pointer to point to the desired part of the string.
Move characters from later in the string to earlier.
Here are sample implementations:
#include <stdio.h>
/* Deletion method 0: Find the first character that is not an "X" and
return its address.
*/
static char *DeleteMethod0(char *string)
{
for (char *p = string; ; ++p)
if (*p != 'X')
return p;
}
// Deletion method 1: Update the pointer to the start of the string.
static void DeleteMethod1(char **string)
{
while (**string == 'X')
++*string;
}
// Deletion method 2: Move characters.
static void DeleteMethod2(char *string)
{
// Find the point where we stop deleting.
char *source = string;
while (*source == 'X')
++source;
// Copy the undeleted part of the string to the start.
while (*source)
*string++ = *source++;
*string = '\0';
}
int main(void)
{
char *string = "XXXXXXXXXXXXTest";
char buffer[] = "XXXXXXXXXXXXTest";
printf("The string is %s.\n", string);
printf("The buffer contains %s.\n", buffer);
char *after = DeleteMethod0(string);
printf("The string after deletion by getting new address %s.\n", after);
DeleteMethod1(&string);
printf("The string after deletion by updating the pointer is %s.\n", string);
DeleteMethod2(buffer);
printf("The buffer after deletion by moving characters is %s.\n", buffer);
}
Another option would be to make a new copy of the desired part of the string, in memory either supplied by the caller or allocated by the deletion routine.
For starters the function should be declared like
char * delChar( char *str );
The function parameter str is a local variable of the function. So this assignment
str = walker;
does not change the pointer myStr declared in main. This pointer is passed to the function by value. That is the function deals with a copy of the pointer. And the assignment does not change the original pointer myStr. It changes only its local variable str that was initialized by a copy of the value of the pointer myStr.
Also you may not change a string literal. Any attempt to change a string literal results in undefined behavior. But you need indeed to change the passed string as at least followed from your assignment
delete leading characters before a string in C
That is the task is not to find the pointer that points to the first character that is not equal to 'X'. You need to remove leading characters equal to 'X' from a string.
In main you need to declare a character array instead of a pointer to a string literal as for example
char myStr[] = "XXXXXXXXXXXXTest";
The function itself can be defined the following way
char * delChar( char *str )
{
char *walker = str;
while ( *walker == 'X' ) ++walker;
if ( walker != str ) memmove( str, walker, strlen( str ) + 1 - ( walker - str ) );
return str;
}
And in main it is enough to write
printf("After function call: %s\n", delChar( myStr ) );
Here is a demonstration program
#include <stdio.h>
#include <string.h>
char * delChar( char *str )
{
char *walker = str;
while (*walker == 'X') ++walker;
if (walker != str) memmove( str, walker, strlen( str ) + 1 - ( walker - str ) );
return str;
}
int main( void )
{
char myStr[] = "XXXXXXXXXXXXTest";
printf( "Before function call: %s\n", myStr );
printf( "After function call: %s\n", delChar( myStr ) );
}
The program output is
Before function call: XXXXXXXXXXXXTest
After function call: Test
The function will be more flexible if to declare a second parameter that will specify a character that should be deleted from the beginning of a string. For example
char * delChar( char *str, char c )
{
if ( c != '\0' )
{
char *walker = str;
while (*walker == c) ++walker;
if (walker != str) memmove( str, walker, strlen( str ) + 1 - ( walker - str ) );
}
return str;
}
In this case the function is called like
printf( "After function call: %s\n", delChar( myStr, 'X'));
str variable in function delChar will created over stack and store address you have passed and will be destroyed when function returns
void delChar(char* str) // str variable will created over stack and store address you have passed and will be destroyed when function returns
{
char* walker; //declare pointer
walker = str; //point to beginning of passed string
while(*walker == 'X') walker++; //move pointer past amy leading 'X'
printf("\nwalker string is now: %s", walker); //prints "Test" as expected
str = walker; //set str pointer to walker
printf("\nstr string is now: %s", str); //prints "Test" as expected
return;
}
After the return str in main will still point to start of the string.
you need to return the address and store
you can track count using counter and return the count Like below
#include<stdio.h>
int delChar(char* str)
{
int count = 0;
while(*str++ == 'X')
count++; // increment the count when x found
printf("\nwalker string is now: %s", str+count);
return count;
}
int main()
{
char* myStr = "XXXXXXXXXXXXTest";
int count;
printf("Before function call: %s", myStr);
count = delChar(myStr);
printf("\nAfter function call: %s", myStr+count);
return 0;
}
Thank you for the thoughtful replies and comments. I infer that this has basically been a question about pointers; that is. modifying a string without needing to return a pointer from a function call. I simplified the example code question for the benefit of those who might be learning as well, with comments (see below). Let me know if I’m off base here...
#include <stdio.h>
#include <stdlib.h>
void func(char** str) //note POINTER-TO-POINTER parameter!
{
printf("\nintial func str: %s", *str); //note dereference before str; prints "FULL TEXT"
*str += 5; //increment pointer five spaces to right to modify the string
printf("\nafter func str: %s", *str); //note dereference before str; prints "TEXT"
}
int main()
{
char* myStr = "FULL TEXT"; //need to initialize string with pointer variable
//char myStr[] = "FULL TEXT"; //initializing string as array will not work for this example!
printf("\n...before MAIN func call: %s", myStr); //prints "FULL TEXT"
/*pass ADDRESS of pointer variable instead of pointer variable itself, i.e. func
parameter needs to be a pointer-to-a-pointer...this is essentially passing by REFERENCE
instead of by VALUE (where a copy would get clobbered when returning to main)*/
func(&myStr); //note ADDRESS symbol, i.e. address of pointer variable
printf("\n...after MAIN func call: %s", myStr); //prints "TEXT", modified string remains after func call
return 0;
}
I have a string like:
my age is 22\r\n\r\n and I live in Rostock
and some other strings like:
I like to swim\r\n\r\n .Yesterday I competed with my 2 friends
Now I want to split a string by \r\n\r\n and have it associated with buffer. Here is what I am trying to do:
char buffer[500];
strcpy(buffer, "my age is 22\r\n\r\n and I live in Rostock");
char *p = buffer;
if((p = strchr(p,"\r\n\r\n"))) {
p[strcspn(p,"tock")] = 0; // trying to slice until the end
}
printf("%s", p);
This gives me a warning as I try to compile saying warning: passing argument 2 of ‘strchr’ makes integer from pointer without a cast I could not understand what this meant.
Also what is good way to split this into 2 char buffers?
strchr expects a mere char and not a string for its second parameter. So you can only pass it a single character.
In C a char is a single character and strings are null terminated char arrays.
What you want to do is probably:
char buffer[500] = "my age is 22\r\n\r\n and I live in Rostock"; // directly initialize the char array
const char sep[] = "\r\n\r\n";
char * p = strstr(buffer, sep); // search the separator
if (p) {
*p = '\0'; // null terminate the first part
p += strlen(sep); // make p point to the start of the second part
printf("%s - %s\n", buffer, p);
}
If you really need to purge the initial part from buffer and have it start at the second part, you could do:
for (char *dest = buffer; p<buffer+sizeof(buffer)-1;) { // do not go past end of array
*dest++ = *p++;
if (*p == '\0') break; // stop on first null
}
I am new to C and I am trying to split a date/time string into separate variables. However, when I step through the code in gdb line by line, it works, however, when I let it run through normally without breakpoints it seg faults and I can't see why.
Below is the code:
char * dateTimeString = "2011/04/16 00:00";
char dateVar[11];
char timeVar[6];
if (splitTimeAndDateString(dateVar, timeVar, dateTimeString))
{
exit(1);
}
printf("Date: %s\tTime: %s\n", dateVar, timeVar);
Below is the function
int splitTimeAndDateString(char date[11], char time[6], char * dateString)
{
char *token;
token = strtok(dateString, " ");
int i = 0;
while (token != NULL)
{
if (i == 0)
{
strcpy(date, token);
}
else if (i == 1)
{
strcpy(time, token);
}
else
{
printf("Overrun date time string\n");
return 1;
}
token = strtok(NULL, " ");
i++;
}
return 0;
}
Thanks for any help you can provide.
The strtok() function modifies string that you wants to parse, and replace all delimiters with \0 nul symbol.
Read: char * strtok ( char * str, const char * delimiters );
str
C string to truncate.
Notice that the contents of this string
are modified and broken into smaller strings (tokens). Alternativelly,
a null pointer may be specified, in which case the function continues
scanning where a previous successful call to the function ended.
In your code:
strtok(dateString, " ");
^
| is a constant string literal
dateString points to "2011/04/16 00:00" a constant string literal, and by using strtok() your code trying to write on read-only memory - that is illegal and this caused segmentation fault.
Read this linked answer for diagram to understand: how strtok() works?
Edit:
#: char * strtok ( char * str, const char * delimiters ); In given code example, str is an array, not constant string literal. Its declaration:
char str[] ="- This, a sample string.";
Here str[] is an nul terminated array of chars, that initialized with string and its length is equals to size of the assigned string. You can change the content of str[] e.g. str[i] = 'A' is a valid operation.
Whereas in your code:
char * dateTimeString = "2011/04/16 00:00";
dateTimeString is pointer to string literal that is not modifiable e.g dateTimeString[i] = 'A' is an illegal operation this time.
I am new to C and I am trying to split a date/time string into separate variables. However, when I step through the code in gdb line by line, it works, however, when I let it run through normally without breakpoints it seg faults and I can't see why.
Below is the code:
char * dateTimeString = "2011/04/16 00:00";
char dateVar[11];
char timeVar[6];
if (splitTimeAndDateString(dateVar, timeVar, dateTimeString))
{
exit(1);
}
printf("Date: %s\tTime: %s\n", dateVar, timeVar);
Below is the function
int splitTimeAndDateString(char date[11], char time[6], char * dateString)
{
char *token;
token = strtok(dateString, " ");
int i = 0;
while (token != NULL)
{
if (i == 0)
{
strcpy(date, token);
}
else if (i == 1)
{
strcpy(time, token);
}
else
{
printf("Overrun date time string\n");
return 1;
}
token = strtok(NULL, " ");
i++;
}
return 0;
}
Thanks for any help you can provide.
The strtok() function modifies string that you wants to parse, and replace all delimiters with \0 nul symbol.
Read: char * strtok ( char * str, const char * delimiters );
str
C string to truncate.
Notice that the contents of this string
are modified and broken into smaller strings (tokens). Alternativelly,
a null pointer may be specified, in which case the function continues
scanning where a previous successful call to the function ended.
In your code:
strtok(dateString, " ");
^
| is a constant string literal
dateString points to "2011/04/16 00:00" a constant string literal, and by using strtok() your code trying to write on read-only memory - that is illegal and this caused segmentation fault.
Read this linked answer for diagram to understand: how strtok() works?
Edit:
#: char * strtok ( char * str, const char * delimiters ); In given code example, str is an array, not constant string literal. Its declaration:
char str[] ="- This, a sample string.";
Here str[] is an nul terminated array of chars, that initialized with string and its length is equals to size of the assigned string. You can change the content of str[] e.g. str[i] = 'A' is a valid operation.
Whereas in your code:
char * dateTimeString = "2011/04/16 00:00";
dateTimeString is pointer to string literal that is not modifiable e.g dateTimeString[i] = 'A' is an illegal operation this time.
/* 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?