I was trying to concatenate 2 strings without using strcat, but I am getting a runtime error. Please, someone help me out here...
Also, is this statement q=q+len; correct? Can we add a variable to a pointer??
#include<stdio.h>
#include<string.h>
void xstrcat(char*,char*);
int main()
{
char source[]="folks";
char target[30]="hello";
xstrcat(target,source);
printf("%s",source);
printf("%s",target);
return 0;
}
void xstrcat(char*p,char*q)
{
int len=0;
len=strlen(q);
q=q+len;
while(*p!='\0')
{
*q=*p;
q++;
p++;
}
*q='\0';
}
Some mistakes in your implementation:
1 - You are accessing random memory. Once you don't have a /0 in your string.
while(*p!='/0')
must be:
while(*p!='\0')
Note the slash \.
2 - You are overwriting random memory when try to add *p into *q. You must create a new variable with enough space for store them.
Also, is this statement q=q+len; correct? Can we add a variable to a
pointer??
Yes. It's a pointer arithmetic expression.
You are passing target as the first parameter in function call, but it seems that the function tries to use the second parameter as the target. So, maybe you would just need yo switch places of parameters in the function call.
Another thing is that you are using slash instead of backslash when escaping the null character. So, change '/0' to '\0'.
Regarding adding int to pointer: in your case in the function that type of pointer arithmetic is perfectly legal.
There are a few things, first, you need to check against \0 and not /0
while(*p!='\0')
But also, you are trying to add a string to a string literal, which will cause undefined behaviour. Switch
xstrcat(target,source);
to
xstrcat(source, target);
Finally, the last line in xstrcat should be changed to
*q='\0';
you are overwriting the memory.
You are concatenating to source which does not have enough memory to hold concatenated characters.
You may want to reverse definition of source and target.
i.e.
char source[30] = "folks";
char *target = "hello";
Or
call xstrcat as xstrcat(source, target);
The problem lies in your code in the below line:
xstrcat(target,source);
It should be
xstrcat(source,target);
or in your xstrcat function, try considering the first parameter as target and second as source.
Related
While working on a CS50 problem set (substitution), I encountered a segmentation fault when running the code. After some searching I found out that assigning memory (malloc) to string "output" fixes the issue. However I wanted to understand why assigning memory is necessary here?
Any explanation would be appreciated.
code extract: -please note i am using the cs50.h library
string cipher(string input, string key) {
string output=malloc(strlen(input)+1);
for (int i=0, len = strlen(input); i<len; i++) {
if(isalpha(input[i]) != 0) {
output[i] = substitute(input[i], key);
}
else {
output[i] = input[i];
}
}
return output;
free(output);
}
As much as I could know about CS50.h string, I came to know that
string output
is just declaring a character pointer named output. So what actually happens in your code is that until you explicitly declare the "strlen(input)+1" contiguous memory locations beloging to output only, they are essentially free locations for the program. Hence, your output pointer will contain only the character at the 0th index. The function returns what "output" actually is, a pointer. Some process within the program meanwhile may make use of all the other memory locations other than output[0], since they never belonged to output string. output only pointed to the first character of some string.
Bound checking in C, C++ is essentially done by the programmer. output[i] for any arbitrary i will never give an error because it's a simple pointer arithmetic for the programmer, i.e. output[i] = *(output+i).
:)
For starters this statement
free(output);
never gets the control because it is placed after the return statement
return output;
and moreover it does not make a sense. It is the caller of the function that is responsible to free the allocated memory.
You need to dynamically allocated memory because otherwise if you will declare a variable length array like
char output[strlen(input)+1];
then after exiting the function it will not be alive and an attempt to access the array outside the function results in undefined behavior.
That is if you will just write
string output;
that is equivalent to
char *output;
then the pointer output has indeterminate value because it was not initialized and neither memory was allocated where the source string will be copied.
You could change the source string input in place without creating one more array.
In this case it would be enough to write
if(isalpha(input[i]) != 0) {
input[i] = substitute(input[i], key);
}
and then you could place the statement
return input;
Pay attention to that using the alias string for the type char * is a bad idea.
The function declaration if to rewrite it like
char * cipher(char *input, char *key);
is confusing. It is unclear whether the strings input and key are being changed within the function or not.
If you want that the function returns a new string build from the source string then the function declaration should look like
char * cipher(const char *input, const char *key);
Thus answering your question
However I wanted to understand why assigning memory is necessary here?
if you want to create a new string from the source string pointed to by the pointer input then it is evident that you need to allocate a new character array where elements of the source string will be copied.
Otherwise if you want to change the source string in place then there is no need to create one more array.
This code is supposed to remove any leading spaces from the given string, and it was working correctly. Then, for seemingly no reason at all, it started removing characters in the middle of the word. In this example the word "CHEDDAR" is given, which has no leading spaces so it should be passed back the same as it was input, however it's returning "CHEDDR" and I have no idea why. Does anyone know how this is even possible? I assume it has to do with pointers and memory, but I am not fluent in C and I need some help. Runnning on RHEL. Thanks.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define REMOVE_LEADING_SPACES(input) \
{ \
stripFrontChar( input, ' ' ); \
}
char *stripFrontChar(char *startingString, char removeChar) {
while (*startingString == removeChar)
strcpy(startingString, startingString + 1);
return (startingString);
}
void main(argc, argv)
char **argv;int argc; {
char *result = "CHEDDAR";
REMOVE_LEADING_SPACES(result);
printf("%s\n", result);
}
EDIT: It's a little late now but based on the comments I should have shown that the word (CHEDDAR I used as an example) is read from a file, not a literal as shown in my code. I was trying to simplify it for the question and I realize now it's a completely different scenario, so I shouldn't have. Thanks, looks like I need to use memmov.
EDIT2: There actually is a space like " CHEDDAR", so I really just need to change it to memmov, thanks again everyone.
You copy a string using overlapping memory area:
strcpy(startingString, startingString + 1);
From the C standard:
7.24.2.3 The strcpy function
If copying takes place between objects that overlap, the behavior is undefined.
You need to use memmov (and provide proper length) or you need to move the characters on your own. You can also improve the performance if you start with counting the characters that need to be removed and then copy all in one go.
Another issue that was pointed out by Joop Eggen in a comment:
char *result = "CHEDDAR";
You are not allowed to modify string literals.
If you try to remove leading characters, you invoke undefined behaviour.
You should change this to
char result[] = "CHEDDAR";
As your sample string does not contain a leading space, this does not cause trouble yet. But you should fix it nevertheless
This code
strcpy(startingString, startingString + 1);
copies overlapping strings.
Per 7.24.2.3 The strcpy function, paragraph 2 of the C standard:
The strcpy function copies the string pointed to by s2 (including the terminating null character) into the array pointed to by s1. If copying takes place between objects that overlap, the behavior is undefined.
You are invoking undefined behavior.
Although the answers identifying that you are copying overlapping strings identify undefined behavior, another cause is that you use a literal string, and on most platforms those are immutable and will cause the program to abort.
Instead of:
char *result = "CHEDDAR";
Use:
char result[] = "CHEDDAR";
(Note: looking at how most strcpy functions will have been implemented, namely a loop that terminates when seeing the null character of the source string, then the overlap that you use will still see the null character of the source and place it in the destination (down-copying). Copying the other way around (up-copying) would not see the null terminator anymore, as it will have been overwritten, and may continue copying beyond the destination string.)
In your case, where no modification is needed and no allocs are done, you only need to find the start without copying anything.
char *stripFrontChar(char *startingString, char removeChar) {
for( ; *startingString == removeChar; startingString++)
;
return (startingString);
}
But you have to use the return of stripFrontChar()
printf("%s\n", stripFrontChar(result));
I am trying to test something and I made a small test file to do so. The code is:
void main(){
int i = 0;
char array1 [3];
array1[0] = 'a';
array1[1] = 'b';
array1[2] = 'c';
printf("%s", array1[i+1]);
printf("%d", i);
}
I receive a segmentation error when I compile and try to run. Please let me know what my issue is.
Please let me know what my issue is. ? firstly char array1[3]; is not null terminated as there is no enough space to put '\0' at the end of array1. To avoid this undefined behavior increase the size of array1.
Secondly, array1[i+1] is a single char not string, so use %c instead of %s as
printf("%c", array1[i+1]);
I suggest you get yourself a good book/video series on C. It's not a language that's fun to pick up out of the blue.
Regardless, your problem here is that you haven't formed a correct string. In C, a string is a pointer to the start of a contiguous region of memory that happens to be filled with characters. There is no data whatsoever stored about it's size or any other characteristics. Only where it starts and what it is. Therefore you must provide information as to when the string ends explicitly. This is done by having the very last character in a string be set to the so called null character (in C represented by the escape sequence '\0'.
This implies that any string must be one character longer than the content you want it to hold. You should also never be setting up a string manually like this. Use a library function like strlcpy to do it. It will automatically add in a null character, even if your array is too small (by truncating the string). Alternatively you can statically create a literal string like this:
char array[] = "abc";
It will automatically be null terminated and be of size 4.
Strings need to have a NUL terminator, and you don't have one, nor is there room for one.
The solution is to add one more character:
char array1[4];
// ...
array1[3] = 0;
Also you're asking to print a string but supplying a character instead. You need to supply the whole buffer:
printf("%s", array1);
Then you're fine.
Spend the time to learn about how C strings work, in particular about the requirement for the terminator, as buffer overflow bugs are no joke.
When printf sees a "%s" specifier in the formatting string, it expects a char* as the corresponding argument, but you passed a char value of the array1[i+1] expression. That char got promoted to int but that is still incompatible with char *, And even if it was it has no chance to be a valid pointer to any meaningful character string...
Note: I can't use any libs or includes!
I have the following Code:
void twstng(char * str, int end, int strt) {
if(strt != end && strt != end-1) {
int hlp = str[strt];
printf("strt %d end %d hlp %d\n", strt, end, hlp);
str[strt] = str[end-1];
printf("test\n");
str[end-1] = hlp;
printf("test\n");
twstng(str, strt+1, end-1);
}
}
and in the main function:
char * sol = "hello";
twisting(sol, 5, 0);
I want to twist the entire string. But the console shows:
strt 0 end 4 help 104
And then comes a memory access error. But why?
My second problem is, that in the original task the given string is a
const char * const str
How can I work with it in the twstng function?
Your char *sol is a pointer to the string "hello". Being a string literal, it is actually read-only, and thus when you pass the pointer to your function, you get an error when you modify the contents of the constant string "hello" through the pointer.
Regarding the second part of the question, const char * const (i.e., constant pointer to a constant char) would indeed be a better type for the pointer, as it would convey that the thing pointed to is constant. However, then you cannot pass this pointer to the function (because the function takes a pointer to a non-const char), and it is not clear from the information given how you are "allowed" to work around this. One way is to copy the string and modify the copy.
edit: And as pointed out by other answers, your recursive call mixes up the start and end arguments (by using the more logical order of start first).
In C all string literals are read-only arrays of characters. It can be stored in memory that is not modifiable, leading to errors such as your when you attempt to modify it. That's why you should always use const char * when referring to string literals.
Use an array instead:
char sol[] = "hello";
I believe the recursive call to 'twstng()' at the bottom of the function has passed the new start and end indexes in the wrong order, given the names in the declaration (or else the declaration has them in the wrong order).
You mixed up your arguments.
Your function declaration says, that the first argument is the end and the second is the strt.
Your recursive call mixes them up.
char *test={"0x11","0x12","0x13","0x00","0x00"};
void change(char* test1, char* test2){
strncpy(test[3], test1, 4);
strncpy(test[4], test2, 4);
}
chage("0x55","0x66");
I can assign the characters to array element directly. However, it will cause the memory leak. That's why I use strncpy() instead.
Please advise if you know how to fix it.
There are at least three two you can get segfault here (one suggestion is to enable compiler warnings - they often pick up "stupid mistakes").
The problem is that test is probably misdeclared, it should probably have been:
char *test[]={"0x11","0x12","0x13","0x00","0x00"};
You initialize a char* with an array of char* which means that you initialize test with the first pointer in that array - which means that test will point to the string literal "0x11", so when you use test[3] as argument to strncpy you will send 1 which is converted to a pointer (probably to address 0x31). strncpy would then try to write to that address which is most probable not allowed. You had nearly a fourth reason here, if you had used test[5] you would asked to access beyond the end of the string which is disallowed (you can access test[4] becase it's the terminating null of the string).
Even if you fix those problems there is a problem because test[3] and test[4] are initialized using a string literal. Then strncpy would try to modify that string literal which is undefined behavior - the segfault is because test[3] and test[4] resides in read-only memory (allowing them to be in read-only memory is one reason why modifying string literals is undefined behavior).
What you instead could have done is to make sure that you have writable copies in test which is maybe not that straight forward in C. One normal solution is to have a function (that you have to call manually) that sets up test, and one that tears it down:
void init_test(void) {
int j;
for(j=0; j<sizeof(test)/sizeof(test[0]); j++)
test[j] = strdup(test[j]);
}
void init_fini(void) {
int j;
for(j=0; j<sizeof(test)/sizeof(test[0]); j++)
free(test[j]);
}
The other answer gives one good reason (never attempt to modify the contents of a string (str(n)cpy does that)).
I'm not even sure you want to represent "characters" as strings, especially as the first declaration doesn't work well (assigning an array of strings to a string).
It will take a lot of work to fix this for sure, but you shall begin by replacing "0x11" by '\x11' (I.E. actually use characters), replace strncpy by mere assignment (true characters are an atomic type which can be assigned directly) and finally change the parameters of the change function to get characters instead of strings.