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.
Related
I have to do an exercise and I have this structure given:
typedef struct {
char *str;
unsigned int len;
} String;
My Task is to write a String Concat which concats "Kartoffel" and "puffer" to "Kartoffelpuffer" (potato fritter).
String concat(String l, String r)
Both Strings l and r should not be changed after running the function.
First I created the two Strings in the main:
String1 *l = malloc(sizeof(String1));
String1 *r = malloc(sizeof(String1));
(*l).str = malloc(sizeof("Kartoffel"));
(*r).str = malloc(sizeof("puffer"));
(*l).str = "Kartoffel";
(*r).str = "puffer";
(*l).len = 9;
(*r).len = 6;
Then I wrote the concat function:
String1 concat(String1 l, String1 r) {
unsigned int i = 0;
String1 *newStr = malloc(sizeof(String1));
/* +1 for '\0' at the end */
newStr->str = malloc(l.len + r.len + 1);
newStr->str = l.str;
/* The following line is not working */
newStr->str[l.len] = *r.str;
newStr->len = l.len + r.len;
return *newStr;
}
What Im trying to do is working with pointer arithmetic.
When there is a pointer which points to the beginning of a storage area like char *str, it should be possible to move the pointer with a[b] or *((a) + (b)) right? When I run the code I get Segmentation fault (I hope its the right translation. Original: "Speicherzugriffsfehler").
If someone could give me a hint I would be thankful. PS: Sorry for my English.
First, (*l).str = "Kartoffel"; makes (*l).str point to the "Kartoffel" string literal, meaning that the original memory allocated to (*l).str with malloc() is lost. Same for (*r).str = "puffer";. One of the things you can do to avoid this is copy the string into the allocated buffer by looping over the characters in a for loop (since you can't use string.h).
Then, in your concat() function, you do the same thing. You allocate the memory for newStr->str with malloc() (properly allocating an extra char for the null-terminator), but on the next line you re-assign that pointer to point to l.str, which is still pointing to the string literal. Then, with newStr->str[l.len] = *r.str; you are attempting to modify the string literal, which in C is undefined behavior.
The way to fix this could be, again, to copy the two strings into the buffer allocated with newStr->str = malloc(l.len+r.len+1);.
After allocating memeory to newStr and newStr->str
Two pointers could be used. char *to, *from;
Set the pointers with to = newStr->str; and from = l.str;
copy the characters with *to = *from;
Advance the pointers with to++; and from++;
Repeat until *from == 0
Set from with from = r.str;
to does not need to be reset as it is correctly positioned at the end of newStr->str.
Repeat the copy of characters.
Repeat advancing the pointers.
Set a terminating 0 with *to = 0;
Thank you very much for your help!
I wrote another method to copy the string as you guys said.
char * copyStr (char * dest,char * src){
unsigned int index;
for (index = 0; src[index] != '\0'; index++) {
dest[index] = src[index];
}
dest[index] = '\0';
return dest;
}
And I edited my concat like that:
String1 concat (String1 l, String1 r){
String1 *newStr = malloc(sizeof(String1));
newStr->str = malloc(l.len+r.len+1);
copyStr(newStr->str,l.str);
copyStr((newStr->str+l.len),r.str);
newStr->len = l.len+r.len;
return *newStr;
}
with newStr->str+l.len the pointer will be moved. If l.len is 9, the pointer will point to the 10th byte, which is the end of the first string l. So the the String r will be copied in the memory storage behind the first string l.
I have a string with the following pattern :
char *str = "ai/aj/module_mat.mod";
and I want to select module_mat as my final string for the further logic. I have tried to used rindex() so that I can get the final part of the string. But I am not able to do this in C. What am I doing wrong?
The code I am trying is -
char *first = rindex(str, "/");
char *first = strtok(first, ".");
Your mistake is right here:
char *str = "ai/aj/module_mat.mod";
Since str points to a constant, this should be:
const char *str = "ai/aj/module_mat.mod";
Now your compiler should show you the other problems.
Similarly:
char *first = rindex(str, "/");
Since rindex is returning a pointer into the constant you passed it, that pointer should also be const.
char *first = strtok(first, ".");
Hmm, what do the docs for strtok say:
If a delimiter byte is found, it is overwritten with a null byte
to terminate the current token, and strtok() saves a pointer to the following byte; ...
So strtok modifies the thing the pointer points to, so passing it a pointer to a constant is bad! You can't modify a constant.
First off, the string literal is immutable, so it is very dangerous to bind it to a mutable char pointer. First fix your code:
const char* str = "ai/aj/module_mat.mod";
Next, use strchr:
#include <string.h>
const char* p = strchr(str, '/');
if (p != NULL) {
++p;
printf("Last part: %s\n", p);
} else {
printf("No '/' found in string %s.\n", str);
}
If a / is found in the string, p will point to it, and hence p can be used as the suffix substring of the original string, and there's no need to modify the original string. We advance p by one to skip past the / and are left with the final part of the string.
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.
I am a beginner in C. I wanted to make strcat function using pointers. I made it but don't know what is wrong with it. I used gcc compiler and it gave segmentation fault output.
#include<stdio.h>
#include<string.h>
char scat(char *,char *);
void main()
{
char *s="james";
char *t="bond";
char *q=scat(s,t);
while(*q!='\0') printf("the concatenated string is %c",*q);
}
char *scat(char *s,char *t)
{
char *p=s;
while(*p!='\0'){
p++;
}
while(*t!='\0'){
*p=*t;
p++;
t++;
}
return p-s-t;
}
This one works:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *scat(char *,char *); /* 1: your prototype was wrong */
void main()
{
char *s="james";
char *t="bond";
char *q=scat(s,t);
printf("cat: %s\n", q); /* 2: you can use %s to print a string */
free(q);
}
char *scat(char *s,char *t)
{
char *p=malloc(strlen(s)+strlen(t)+1); /* 3: you will have to reserve memory to hold the copy. */
int ptr =0, temp = 0; /* 4 initialise some helpers */
while(s[temp]!='\0'){ /* 5. use the temp to "walk" over string 1 */
p[ptr++] = s[temp++];
}
temp=0;
while(t[temp]!='\0'){ /* and string two */
p[ptr++]=t[temp++];
}
return p;
}
You have to allocate new space to copy at the end of s. Otherwise, your while loo[ will go in memory you don't have access to.
You shoul learn about malloc() here.
It is undefined behaviour to modify a string literal and s, and eventually p, is pointing to a string literal:
char* s = "james";
s is passed as first argument to scat() to which the local char* p is assigned and then:
*p=*t;
which on first invocation is attempting to overwite the null character an the end of the string literal "james".
A possible solution would be to use malloc() to allocate a buffer large enough to contain the concatentation of the two input strings:
char* result = malloc(strlen(s) + strlen(p) + 1); /* + 1 for null terminator. */
and copy them into it. The caller must remember to free() the returned char*.
You may find the list of frequently asked pointer questions useful.
Because p goes till the end of the string and then it starts advancing to illegal memory.
That is why you get segmentation fault.
It's because s points to "james\0", string literal & you cannot modify constant.
Change char *s="james"; to char s[50]="james";.
You need to understand the basics of pointers.
a char * is not a string or array of characters, it's the address of the beginning of the data.
you can't do a char * - char* !!
This is a good tutorial to start with
you will have to use malloc
You get a segmentation fault because you move the pointer to the end of s and then just start writing the data of p to the memory directly following s. What makes you believe there is writable memory available after s? Any attempt to write data to non-writable memory results in a segmentation fault and it looks like the memory following s is not writable (which is to expect, since "string constants" are usually stored in read-only memory).
Several things look out of order.
First keep in mind that when you want to return a pointer to something created within a function it needs to have been malloc'ed somewhere. Much easier if you pass the destination as an argument to the function. If you follow the former approach, don't forget to free() it when you're done with it.
Also, the function scat has to return a pointer in the declaration i.e. char *scat, not char scat.
Finally you don't need that loop to print the string, printf("%s", string); will take care of printing the string for you (provided it's terminated).
At first, your code will be in infinte loop because of the below line. you were supposed to use curely braces by including "p++; t++ " statements.
while(*t!='\0')
*p=*t;
though you do like this, you are trying to alter the content of the string literal. which will result in undefined behavior like segmentation fault.
A sequence of characters enclosed with in double quotes are called as string literal. it is also called as "string". String is fixed in size. once you created, you can't extend its size and alter the contents. Doing so will lead to undefined behavior.
To solve this problem , you need to allocate a new character array whose size is sum of the length of two strings passed. then append the two strings into the new array. finally return the address of the new array.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char* scat(char *,char *);
void append(char *t , char *s);
int main(void)
{
char *s="james";
char *t="bond";
char *n = scat(s,t);
printf("the concatenated string is %s",n);
return 0;
}
char* scat(char *s,char *t)
{
int len = strlen(s) + strlen(t);
char *tmp = (char *)malloc(sizeof(char)* len);
append(tmp,s);
append(tmp,t);
return tmp;
}
void append(char *t , char *s)
{
//move pointer t to end of the string it points.
while(*t != '\0'){
t++;
}
while( *s != '\0' ){
*t = *s;
t++;
s++;
}
}
I tried to code a function which replace all string s1 to s2, in a given string s.
however, i don't know why my program stop at the line *p=0 in that replace function without any error reported? ##
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void replace(char * s, char * s1, char * s2) {
char * p; int l=strlen(s2);
while ((p=strstr(s,s1))) {
*p=0;
p+=l;
strcat(s,s2);
strcat(s,p);
}
}
int main(void) {
char *s=(char *)"cmd=ls+-la&abc=xyz";
replace (s, "+", " ");
printf("%s", s);
return EXIT_SUCCESS;
}
There are some problems with the replace function but, first of all, there is a big difference between a pointer to a constant char array vs a character array:
char *str = "some string";
Assigns str the address of the immutable character array (read-only), it does not copy the string, only pointers are involved. Any attempt to modify that string will result in undefined behavior.
char str[] = "some string";
In this case str is an array (of size big enough to hold the string + \0) that is initialized to that string, allowing the modification of individual characters within the array.
Back to your replace function.
I will start with the first thing that I saw which is your use of strstr and strcat inside the loop is highly inefficient. Every time you call strstr it starts from the beginning of the string and searches for the first occurrence of the second string all over, the same problem can be seen with strcat which needs to find the null-terminator every time.
Another issue I see is if the replacement string (s2) is longer than the original string (s1) you must shift the entire string to accommodate for the additional characters of the new string. The same issue will occur if the replacement string is shorter.
a basic method to replace a simple char might look like this:
while (*s)
{
if (*s == c1)
*s = c2;
++s;
}
a little more complex method to replace a string would be:
/* PRECONDITION: strlen(s1) == strlen(s2) */
int l = strlen(s2);
while (*s)
{
if (!strncmp(s, s1, l))
{
memcpy(s, s2, l);
s += l;
}
else
++s;
}
Your compiler is allowed to place string literals into read-only memory, which is probably what it did with s.
Try:
char s[] = "cmd=ls+-la&abc=xyz";
This changes s from a pointer to a string literal into an array initialized with your string.