The function is to reverse a C string:
void reverse(char[] str){
char *start = str;
char *end = str;
char tmp;
if (str) {
while (*end) {
end++;
}
end--;
while (&str > &end) {
tmp = *str;
*str = *end;
str++;
*end=tmp;
end--;
}
}
}
In the last while loop, when I assign *end to *str, this line is causing a bus error, Could anyone please explain why?
btw, what is the difference between a
char[] temp and char temp[]?
This loop condition:
while (&str > &end)
is wrong. You don't want the & operators, and you also have it backwards. Use:
while (str < end)
Besides that, as I mentioned in my comment above, you need to declare your function signature properly, too:
void reverse(char str[])
while (&str > &end) {
This line is wrong. & yields the address, and the addresses of these pointer variables doesn't change during the loop. You don't want the addresses of the pointers, you want their values, and you want to loop until the start reaches the end, so:
while (str < end) {
Or
while (start < end) {
and change the other instances of str to start as appropriate ... or get rid of your unused start variable.
btw, what is the difference between a char[] temp and char temp[]?
The former isn't legal C.
Update:
The newly posted code looks ok, but its behavior is undefined if the argument is invalid or non-writable ... for example, a string literal. A full answer requires that you post a
Short, Self Contained, Compilable Example.
Related
EDIT: I think I've understood how this concept works, this is my code
void delete_duplicate(char* str) {
if (str == NULL) {
exit(1);
}
for (size_t i = 0; str[i] != 0; i++) {
if (str[i] == str[i + 1]) {
str[i] = '\0';
}
}
}
int main(void) {
char str[] = "hhhhhhhheeeeeeeeyyyyyyyyyyy";
delete_duplicate(str);
return 0;
}
the output string is "00...0h0...000e0...000y" (with lots of zeros). if the string is "abbbb", the string becomes "a" and not "ab".
I was thinking about an algorithm for this exercise:
given a string, for example "ssttringg" the output must be "string". the function has to remove one character if and only if the current character and the next character are the same.
the exercise expects a function declared like this:
extern void delete_consecutive(char* str);
this is my algorithm:
loop: if the current character is equal to the next character, increment length by 1, and repeat until zero terminator is reached.
critical part: dynamic memory allocation.
allocate enough memory to store the output. Why did I say this is the critical part? because I have to do it in a void function, therefore I can't create a second string, allocate enough memory with malloc, and then return it at the end. I need to edit the original string instead. I think I can do it by means of a realloc, and by decrementing the size of the string. But I don't know how to do it, and more important: I don't know if it's legit to do it, without losing data. I think I'm overcomplicating the homework, but it's a void function, therefore I can't simply create a new string and copying characters in it, because I can't return it.
if it's not clear, I'll edit the question.
This pattern is called a retention scan (also a reduction scan, depending on your perspective), and is very common in algorithms that dictate discarding characters whilst keeping others, based on some condition. Often, the condition can change, and sometimes even the methods for starting the scan are somewhat altered
In it's simplest form, it looks something like this, as an example: An algorithm used to discard all but numeric (digit) characters:
Start with reader r and writer w pointers at the head of the string.
Iterate over the string from beginning to terminator using r. The r pointer will always be incremented exactly once per iteration.
For each iteration, check to see if the current character at r satisfies the condition for retention (in this case, is the character a digit char?). If it does, write it at w and advance w one slot.
When finished. w will point to the location where your terminator should reside.
#include <ctype.h>
void delete_nondigits(char *s)
{
if (s && *s)
{
char *w = s;
for (char *r = s; *r; ++r)
{
if (isdigit((unsigned char)*r))
*w++ = *r;
}
*w = 0;
}
}
Pretty simple.
Now, the algorithm for in-place consecutive-run compaction is more complicated, but has a highly similar model. Because retention is based on a prior-value already-retained you need to remember that last-kept value. You could just use *w, but the algorithm is actually easier to understand (and advance w) if you keep it in a separate memo char as you're about to see:
Start with reader r and writer w pointers as we had before, but starting at second slot of the string, and a single memo char variable c initialized to the first character of the string.
Iterate over the string using r until termination encounter. The r pointer will always be incremented exactly once per iteration.
For each iteration, check to see if the current character at *r is the same as the memo character c If it is, do nothing and continue to the next iteration.
Otherwise, if the character at *r is different than the memo character c, save it as the new value for c, write it to *w, and advance w one slot.
When finished, terminate the string by setting a terminator at *w.
The only hitch to this algorithm is supporting a zero-length string on inception, which is easily circumvented by checking that single condition first. I leave actually implementing it as an exercise for you. (hint: only do the above if (s && *s) is true).
You can modify the string passed as a parameter if it is modifiable.
Example:
void deleteFirstChar(char *str)
{
if(str && *str)
{
memmove(str, str + 1, strlen(str));
}
}
//illegal call
//string literals cannot be changed
void foo(void)
{
char *str = "Hello";
deleteFirstChar(str);
}
//legal call
void bar(void)
{
char str[] = "Hello";
deleteFirstChar(str);
}
This isn't an answer, but consider this code:
char str[] = "strunqg";
printf("before: %s\n", str);
modifystring(str);
printf("after: %s\n", str);
where the "modifystring" function looks like this:
void modifystring(char *p)
{
p[3] = 'i';
p[5] = p[6];
p[6] = '\0';
}
This is totally "legit". It would not work, however, to call
char *str = "strunqg";
modifystring(str); /* WRONG */
or
modifystring("strunqg"); /* WRONG */
Either of these second two would attempt to modify a string literal, and that's not copacetic.
void delete_duplicate(char* str)
{
if(str && *str)
{
char *writeTo = str, *readFrom = str;
char prev = 0;
while(*readFrom)
{
if(prev != *readFrom)
{
prev = *readFrom++;
*writeTo++ = prev;
}
else
{
readFrom++;
}
}
*writeTo = 0;
}
}
int main(void)
{
char str[] = "hhhhhhhheeeeeeeeyyyyyyyyyyy";
delete_duplicate(str);
printf("`%s`\n", str);
return 0;
}
There is pointer to string let say: char *p = "abcdef"
I want to delete some of the chars.
Let say every second char, so i want to get *p="ace"
my algorithm is something like:
int i=1,j=1
for(;p != '\0';p++,i++)
if (i % 2 ==0)
*(p - j++)= *p
*(p-j)='\0'
This algorithm is find the every second char of course but not matter how I try to write the "delete" process or there are compilation errors or the string is unchanged.
I start to believe there is no way to solve that issue without any malloc help.
Again i need to do it on O(n) without any other STRINGS arrays.
p != '\0' should be *p != '\0'(or *p != 0 or *p).
i should be initialized to 0. (You are keeping the wrong ones.)
j should be initialized to 0. (Off by one error.)
j needs to be incremented each time p is incremented.
Your code would be more readable and less fragile if you avoided offsets relative to an unrelated pointer.
void filter_inplace(char* src) {
char* dst = src;
for (size_t i=0; src[i]; ++i) {
if (i % 2 == 0)
*(dst++) = src[i];
}
*dst = 0;
}
Alternative:
void filter_inplace(char* src) {
char* dst = src;
while (1) {
if (!*src) break;
*(dst++) = *(src++);
if (!*src) break;
src++;
}
*dst = 0;
}
Of course, you can't do the following because p points to read-only memory:
char* p = "abcdef"; # XXX Should be "const char*".
filter_inplace(p); # XXX Overwrites read-only memory.
You could do the following:
char p[] = "abcdef";
filter_inplace(p);
You could do the following:
char* p = strdup("abcdef");
filter_inplace(p);
free(p);
I start to believe there is no way to solve that issue without any malloc help. Again i need to do it on O(n) without any other STRINGS arrays.
Kind of true. At least it is true that it can't be done without another string. Even if you used malloc (or strdup) for getting memory I would still consider it another string.
So as long a you initialize the char pointer like:
char *p = "abcdef";
it can not be done. You can't change any character in the string "abcdef".
If the above code was changed to
char p[] = "abcdef";
you would be able to do what you a trying. But even this could be considered as using another string as you have both the initializer string and char array.
I know that this strcpy function below is incorrect, but I cannot seem to figure out the one or two things I need to change to fix it. Any help would be greatly appreciated as I am completely stuck on this:
void strcpy(char *destString, char *sourceString)
{
char *marker, *t;
for(marker = sourceString, t = destString; *marker; marker++, t++)
*t = *marker;
}
Well it depends on your environment..
For example I see a few things I don't like:
You do not check for input parameters to be != NULL. This will cause a *0 access
I see you are not terminating your string with the '\0' character (or 0).. So, after the loop (please intent.) add *t = 0;
strcpy() is a predefined function and you are trying to create your own strcpy function. so, when you compile your program, you are getting conflicting types error. So, first rename your function name.
If you want to implement your own strcpy(), then i would suggest to implement strncpy(). It will copy at-most n-1 bytes from source null-terminated character array to destination character array and also add null character at the end of the destination character array.
void strcpy(char *dest, const char *src, size_t n)
{
if ((dest == NULL) || (src == NULL))
return;
int i;
for(i=0; i<(n-1) && src[i]; i++)
dest[i] = src[i];
dest[i]='\0';
}
It wouldn't let buffer overflow.
Note - My implementation is different from standard library strncpy() implementation. The standard library function strncpy() copies at most n bytes of src. If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.
I know that this strcpy function below is incorrect, but I cannot seem to figure out the one or two things I need to change to fix it.
You only need to add null character at the end of destination array.
void strcpy(char *destString, char *sourceString)
{
char *marker, *t;
for(marker = sourceString, t = destString; *marker; marker++, t++)
*t = *marker;
*t='\0';
}
This is a very simple aproach:
void copy(char * src, char * dst){
while(*src != '\0'){
*dst = *src;
src++;
dst++;
}
*dst = '\0';
}
int main(int argc, char** argv){
char src [] = "hello";
char dst [] = "----";
copy(src, dst);
printf("src: %s\n", src);
printf("dst: %s\n", dst );
}
It's more or less like wildplasser comment. First you iterate over the src pointer. In c, if you have '\0' (in a well formed string) then you can exit because it is the final character. Ok, you iterate over the src pointer and assign the value of src (*src) to the value of dst (*dst) and then you only have to increase both pointers...
It's all
A very easy strcpy function would be:
int strcpy(char *dest,char *source)
{
if (source==NULL)
{
printf("The source pointer is NULL");
return 0;
}
if (dest==NULL)
{
dest=(char*)malloc((strlen(source)+1)*sizeof(char));
}
int i;
for (i=0;source[i]!='\0';i++)
{
dest[i]=source[i];
}
dest[i]='\0';
return 1;
}
You should have no problem copying strings this way. Always use indexes instead of pointer operations, it's easier imo.
If you use an IDE, you should learn to use the debug function to discover the errors and problems, usually when you deal with strings one of the most common RUNTIME problems is the lack of a '\0', which automatically make your string functions go to memory zones where they shouldn`t be.
I am trying to understand this algorithm, which reverses a C-style character in-place. I don't understand what the * indicates in the context of being before a string and in the context of "char * end." Thanks for your help!
void reverse(char *str) {
char * end = str;
char tmp;
if (str) {
while (*end) {
++end;
}
--end;
while (str < end) {
tmp = *str;
*str++ = *end;
*end-- = tmp;
}
}
}
You are really interested in learning then you need to learn basic of c first then pointer:
This one is a very quick tutorial of pointers : http://www.programiz.com/c-programming/c-pointers then go through this and see string as pointer : https://www.cs.bu.edu/teaching/c/string/intro/
I will suggest to go through them once help you in understanding many things in other languages also. :)
It's a character pointer when you use a "" before a string..
This is also treated as character array where the string entered after"" will be the name of that array.
The asterisk refers to a pointer
char tmp
This is a character
char * str
This is a pointer to a char (or char array in this case).
tmp = *str;
Means that the character tmp is filled with the first character from the string array pointed to by the pointer str.
Good evening, I have 2 functions and each of them accepts as argument a pointer to char:
char pointer[255];
func1(char* pointer)
{
...
memcpy(pointer,some_char,strlen(something));
return;
}
func2(char* pointer)
{
...
if (pointer==someother_char) exit(0); //FAILs
//also I have
if(pointer==someother_pointer2char); // FAILs
}
Now I've tried strstr,strcmp etc... doesn't work. Wanted to try memcmp but I don't have static len. As I have to compare char* to char and char* to char* I would be needing two solutions right?
So, how to compare these pointers (actually pointees) in shortest possible way?
Thanks.
E D I T
Thanks to wallacer and Code Monkey now for char* to char comparison I use following:
func1(char* ptr){
char someother_char[255];
char *ptr_char = NULL; //I have to strcmp a few values so this is why I initialize it first
...
ptr_char = someother_char;
if (strcmp(ptr,ptr_char) == 0) //gtfo and it does...
...
ptr_char = some2nd;
if(strcmp...
Any suggestions maybe... (hmm external function for comparing?)
Suggestion1(by Code Monkey)
#include <stdio.h>
int main(void) {
char tempchar[255];
tempchar[0] = 'a';
tempchar[1] = 'b';
tempchar[2] = '\0';
char *ptr_char;
ptr_char = &tempchar[0];
printf("%s", ptr_char);
return 0;
}
You need to use strcmp. Not seeing how you tried to use it, this is how you should use it:
char *someother_char = "a";
char *pointer = "a";
if (strcmp(pointer, someother_char) == 0) { // match!
}
else { // not matched
}
to then do the comparison with a char, you have to promote to a char*:
char *someother_char1;
char test = 'a';
char *pointer = "a";
strncpy((char*)test,someother_char1,sizeof(test));
if (strcmp(pointer, someother_char1) == 0) { // match!
}
else { // not matched
}
if you want to use the char array then you have to de-reference:
char char_array[255];
// don't forget to fill your array
// and add a null-terminating char somewhere, such as char_array[255] = '\0';
char *ptr_somechar = &char_array[0];
char *pointer = "a";
if (strcmp(pointer, ptr_somechar) == 0) { // match!
} else { // not matched
}
Well right off the bat, if you want to compare the pointees, you need to dereference them. This means to compare the actual char value, you'll have to call
if (*pointer == someother_char)
However this will only compare the first char in the array, which is probably not what you want to do.
To compare the whole thing strcmp should work
char* someother_str = "hello strstr";
if(strcmp(pointer, someother_str) == 0) {
// do something
}
Make sure your other string is declared as a char*
More info: http://www.cplusplus.com/reference/clibrary/cstring/strcmp/
Edit: as per your comment. comparing char* and char doesn't really make sense. One is a character value, the other is an address in memory. Do do so, you can either dereference the char* or reference the value variable.
char c;
char* ptr;
// dereference ptr
if ( c == *ptr ) {
...
}
// reference the value
if ( &c == ptr ) {
}
The first method checks if the values are the same. The second checks if ptr is in fact pointing to the memory containing c ie. is ptr a pointer to c
Hope that helps
Use function srtncmp no srtcmp.
int res = strncmp(str, "¿Cuál es tu nombre? ", 100);
See the next link
compare strings
Strings are null terminated. When you use such kind of strings, it's not a good idea to mixing with other memory copy functions.
Once you do the memcpy operation, please note that your destination string will not be null terminated.
memcmp is a fast operations. Otherwise yo can simply loop through each character and quit upon finding a difference.
To use strcmp, please make sure that both the strings are null terminated. Otherwise it will lead to some crash.
I suggest you to use string functions like strcmp,strlen, strcpy to deal with strings because for that it's actually implemented.
You can't compare two pointers unless both pointers are referring to same memory location. Pointer is just a address to a memory location. What you really want to do is that, to compare the contents rather than compare the address where it's stored. So please use strcmp but again I warn you make sure that it's null terminated.