How would I append a char to string that has no initial value in the following method I've started:
void append(char a) {
const char *str;
char *ret = malloc (strlen(str)+2);
strncpy(str,strlen(str),ret);
ret[strlen(str)-2] = a;
ret[strlen(str)-1] = 0;
printf("%s", str);
}
I've tried a few different answers to other questions but none have worked, please help.
Since the pointer str is not initialized, you can't add characters to what it points at. What makes sense depends on what you're going to do next. Since you don't return a value from the function, you can't access the string to which a is appended unless append calls some other function.
char *str; is not a string. It is a mnemonic that says that *str will give you a value which is supposedly a character.
str is a pointer that points at random. Make it point to an allocated bunch of memory first.
Do something like- str = malloc(100); and then do a *(str+1) = a and then a *(str+2) = '\0' to NULL terminate the string.
how about something like:
char * append(char a, const char * str)
{
char *ret = malloc (strlen(str)+2);
strncpy(str,strlen(str),ret);
ret[strlen(str)-2] = a;
ret[strlen(str)-1] = 0;
return ret;
}
Related
Looking at this code from The Evils of Arduino Strings
void PrintString(const char *str) {
const char *p;
p = str;
while (*p) {
Serial.print(*p);
p++;
}
}
I was looking at reducing/compacting it. Firstly, this seems to be equivalent:
void PrintString(const char *str) {
const char *p;
p = str;
while (*p)
Serial.print(*p++);
}
Now, looking at the first two lines, how can I combine the following two lines, is it possible?
const char *p;
p = str;
Can I do this?
const char *p = str;
This would seem likely but looks unbalanced, in that there is a lack of an asterisk on the right hand side. I tried it and it seems to work but I was wondering whether it was correct, and worried that I would end up with some hard-to-track-down run-time error later on, further down the line.
However, this line below is clearly wrong (as it would change the pointer p to point to a location given by the value of the first character of the C string str):
const char *p = *str;
This is obfuscation. The original code is perfectly clear, there is no need to change anything. Your changes make it less readable.
What you can do to increase readability slightly, and this is a cosmetic change, is to use a for loop instead:
void PrintString (const char *str)
{
for(const char* p=str; *p != '\0'; p++)
{
Serial.print(*p);
}
}
Alternatively:
void PrintString (const char *str)
{
for(size_t i=0; str[i] != '\0'; i++)
{
Serial.print(str[i]);
}
}
const char *p = str;
This would seem likely but looks unbalanced, in that there is a lack of an asterisk on the right hand side.
If you separated the elements of the above snippet correctly it would not look "unbalanced" at all:
const char* is the type (a pointer to const characters)
p and str are the variables, both pointer (to const char)
You could write the above using some unconventional layout like this:
const char * /* Note the lack of a semicolon */
p = str;
The above code ends up with p being defined as a pointer to char and carrying the value of str.
You get same "result" for the below code
const char *p;
p = str;
Note that the former is called "initialisation", whereas the latter is called "assignment".
You can omit the use of the p pointer, use directly the str pointer argument, since it is a copy of the pointer to the constant content.
The changes made on str pointer don't affect the pointer used when calling the function, since the pointer is passed by value.
void PrintString(const char *str) {
while (*str) Serial.print(*str++);
}
How about replacing the while with for. Here's my take:
void PrintString(const char *str)
{
for(const char* p = str; *p; p++)
Serial.print(*p);
}
I think this could work, too:
void PrintString(const char *str) {
for(const char* p = str; *p; Serial.print(*(++p)))
;
}
As others have pointed out, we can replace p with str, since str is a local copy, just like any other variable passed as function argument.
void PrintString(const char* str) {
for( ; *str; Serial.print(*(++str)))
;
}
I'm fairly new to C and I'm a little confused as to the correct way to initialise struct variables which are pointers, within a function. Is this style sufficient, or do I need to allocate memory before I assign s->str?
Thank you kindly for your replies, apologies if the question is unclear as I am very new to this language.
typedef struct Mystruct{
const char* str1;
const char* str2;
}mystruct;
mystruct* mystruct_new(const char* str1, const char* str2){
mystruct *s = (mystruct*)(malloc(sizeof(mystruct)));
s->str1 = str1;
s->str2 = str2;
return s;
}
your function is legal and doesn't do anything bad. Nevertheless, you should document it to mention that the strings are not copied, only the pointers are.
So if the passed data has a shorter life than the structure itself, you may meet undefined behaviour. Example:
mystruct*func()
{
char a[]="foo";
char b[]="bar";
return mystruct_new(a,b);
}
mystruct*func2()
{
char *a="foo";
char *b="bar";
return mystruct_new(a,b);
}
int main()
{
mystruct *s = func();
printf(s->a); // wrong, memory could be trashed
mystruct *s2 = func2();
printf(s2->a); // correct
mystruct *s3 = mystruct_new("foo","bar");
printf(s3->a); // also correct, string literals have global scope
}
the above code is undefined behaviour for the first print because s->a points to some memory that is no longer allocated (local to func).
The second print is OK because s2->a points to a string literal which has infinite life span.
So maybe your function is more useful like this:
mystruct* mystruct_new(const char* str1, const char* str2){
mystruct *s = malloc(sizeof(mystruct));
s->str1 = strdup(str1);
s->str2 = strdup(str2);
return s;
}
now the memory is allocated for the strings. Don't forget to free it when discarding the structure, better done in another utility function.
If the strings being passed in to str and str2 will always be string constants than yes you can get away with doing it this way. My guess however is that this is not the case. So you would be better off making a copy of each string with strdup and assigning those to the struct members:
mystruct* mystruct_new(const char* str1, const char* str2){
mystruct *s = malloc(sizeof(mystruct));
s->str1 = strdup(str1);
s->str2 = strdup(str2);
return s;
}
Just make sure to free each of those fields before freeing the struct.
Think of it this way: when you allocate memory for the struct, you get the pointer member variables for free. So in essence, when you do this:
mystruct *s = malloc(sizeof(mystruct)); //don't cast result of malloc.
Then you can treat s->str1 in the exact same way as you would any regular char* variable, say
char *str1 = NULL;
If you want it to point to something, then you have to allocate memory for the pointers. Consider this:
mystruct* mystruct_new(const char* str1, const char* str2){
mystruct *s = malloc(sizeof(mystruct);
char* someString = getMyString(); //gets some arbitrary string
char* str1 = NULL;//just for demonstration
int length = strlen(someString) + 1;
//for struct members
s->str1 = malloc(sizeof(char) * length);
strcpy(s->str1, someString);
//For regular pointers
str1 = malloc(sizeof(char) * length);
strcpy(str1, someString);
return s;
}
Also note that if you just assign to a pointer by using the = operator instead of allocating memory, then it will only copy the address to the original value. This may or may not be what you want depending on the context. Generally, if you know the memory location will stay in scope and you don't need (or don't mind) to change the original string, then it is preferred to simply assign it. Otherwise, it is advisable to make a copy.
//Makes a copy of the string
s->str1 = malloc(sizeof(char) * length);
strcpy(s->str1, someString);
//copies the address of the original value only!
s->str1 = someString;
Use strncpy() instead of strcpy(). The latter is subject to buffer overruns.
For example in this code snippet given by another user, use the strncpy() in place of strcpy()
mystruct* mystruct_new(const char* str1, const char* str2){
mystruct *s = malloc(sizeof(mystruct);
char* someString = getMyString(); //gets some arbitrary string
char* str1 = NULL;//just for demonstration
int length = strlen(someString) + 1;
//for struct members
s->str1 = malloc(sizeof(char) * length);
strcpy(s->str1, someString);
//For regular pointers
str1 = malloc(sizeof(char) * length);
strcpy(str1, someString); // replace with strncpy(str1, someString, bufsize); where bufsize is the maximum number of characters in your string + 1 for the terminator '\0'.
return s;
}
I have the following program:
#include <stdio.h>
#define MAXLEN 100
char *my_strcat(char *strp1,char *strp2) {
char str[MAXLEN], *strp;
strp = str;
while (*strp1 != '\0') {
*strp++ = *strp1++;
}
while (*strp2 != '\0') {
*strp++ = *strp2++;
}
*strp = '\0';
strp = str;
return strp;
}
void test_strcat(void) {
char *strp1, *strp2, *strp3, str1[MAXLEN], str2[MAXLEN];
printf("Testing strcat! Give two strings:\n");
gets_s(str1, sizeof(str1));
gets_s(str2, sizeof(str2));
strp1 = str1;
strp2 = str2;
strp3 = my_strcat(strp1, strp2);
printf("Concatenated string: %s", strp3);
}
int main(void) {
test_strcat();
}
The function char *mystrcat is supposed to concatenate two strings, and I test it with
test_strcat. The program runs without errors but instead of printing the concatenated string a smiley symbol is printed. I have gone through the program with debugging and it
appears that the result sent back by my_strcat is the correct string. However, when
going into the last line where strp3 is supposed to be printed it appears red in the
debugging tool, implying that its value is about to change. After the printf call, strp3
no longer points to the concatenated string. Anyone knows what could be causing this error?
Here is the problem:
char str[MAXLEN], *strp;
strp = str; // str is a local variable
...
return strp; // <<== WRONG!!!
Since str is a local variable that disappears as soon as you return, the value pointed to by strp becomes invalid the instance the caller gets the control back.
Use malloc instead of allocating memory in the automatic storage area (i.e. on the stack) will fix this problem:
char *str = malloc(strlen(strp1)+strlen(strp2)+1);
char *strp = str;
I suggest you 2 ways as following.
first,
char *my_strcat(char *strp1,char *strp2) {
static char str[MAXLEN * 2]; /* from char str[MAXLEN] */
second,
char *my_strcat(char *strp1,char *strp2) {
char *str = malloc(strlen(strp1) + strlen(strp2) + 1);
because in my_strcat function, you allocated the str as auto variable.
When my_strcat function is finish, str will be freed.
I have writen a code to split the string with multiple char delimiter.
It is working fine for first time of calling to this function
but i calling it second time it retuns the correct word with some unwanted symbol.
I think this problem occurs because of not clearing the buffer.I have tried a lot but cant solve this. please help me to solve this problem.
char **split(char *phrase, char *delimiter) {
int i = 0;
char **arraylist= malloc(10 *sizeof(char *));
char *loc1=NULL;
char *loc=NULL;
loc1 = phrase;
while (loc1 != NULL) {
loc = strstr(loc1, delimiter);
if (loc == NULL) {
arraylist[i]=malloc(sizeof(loc1));
arraylist[i]=loc1;
break;
}
char *buf = malloc(sizeof(char) * 256); // memory for 256 char
int length = strlen(delimiter);
strncpy(buf, loc1, loc-loc1);
arraylist[i]=malloc(sizeof(buf));
arraylist[i]=buf;
i++;
loc = loc+length;
loc1 = loc;
}
return arraylist;
}
called this function first time
char **splitdetails = split("100000000<delimit>0<delimit>hellooo" , "<delimit>");
It gives
splitdetails[0]=100000000
splitdetails[1]=0
splitdetails[2]=hellooo
but i called this second time
char **splitdetails = split("20000000<delimit>10<delimit>testing" , "<delimit>");
splitdetails[0]=20000000��������������������������
splitdetails[1]=10����
splitdetails[2]=testing
Update:-
thanks to #fatelerror. i have change my code as
char** split(char *phrase, char *delimiter) {
int i = 0;
char **arraylist = malloc(10 *sizeof(char *));
char *loc1=NULL;
char *loc=NULL;
loc1 = phrase;
while (loc1 != NULL) {
loc = strstr(loc1, delimiter);
if (loc == NULL) {
arraylist[i]=malloc(strlen(loc1) + 1);
strcpy(arraylist[i], loc1);
break;
}
char *buf = malloc(sizeof(char) * 256); // memory for 256 char
int length = strlen(delimiter);
strncpy(buf, loc1, loc-loc1);
buf[loc - loc1] = '\0';
arraylist[i]=malloc(strlen(buf));
strcpy(arraylist[i], buf);
i++;
loc = loc+length;
loc1 = loc;
}
}
In the caller function, i used it as
char *id
char **splitdetails = split("20000000<delimit>10<delimit>testing" , "<delimit>");
id = splitdetails[0];
//some works done with id
//free the split details with this code.
for(int i=0;i<3;i++) {
free(domaindetails[i]);
}free(domaindetails);
domaindetails=NULL;
then i called the same for the second as,
char **splitdetails1= split("10000000<delimit>1000<delimit>testing1" , "<delimit>");
it makes error and i can't free the function.
thanks in advance.
Your problem boils down to three basic things:
sizeof is not strlen()
Assignment doesn't copy strings in C.
strncpy() doesn't always nul-terminate strings.
So, when you say something like:
arraylist[i]=malloc(sizeof(loc1));
arraylist[i]=loc1;
thisdoes not copy the string. The first one allocates the size of loc1, which is a char *. In other words, you allocated the size of a pointer. You want to allocate storage to store the string, i.e. using strlen():
arraylist[i]=malloc(strlen(loc1) + 1);
Note the + 1 as well, because you also need room for the nul-terminator. Then, to copy the string you want to use strcpy():
strcpy(arraylist[i], loc1);
The way you had it was just assigning a pointer to your old string (and in the process leaing the memory you had just allocated). It's also common to use strdup() which combines both of these steps, i.e.
arraylist[i] = strdup(loc1);
This is convenient but strdup() is not part of the official C library. You need to assess the portability needs of your code before you consider using it.
Additionally, with strncpy(), you should be aware that it does not always nul-terminate:
strncpy(buf, loc1, loc-loc1);
This copies less bytes than were in the original string and doesn't terminate buf. Thus, it's necessary to include a nul terminator yourself:
buf[loc - loc1] = '\0';
This is the root cause of what you are seeing with the garbage. Since you didn't nul terminate, C doesn't know where your string ends and so it keeps on reading whatever happens to be in memory.
So, I have seen this strcpy implementation in C:
void strcpy1(char dest[], const char source[])
{
int i = 0;
while (1)
{
dest[i] = source[i];
if (dest[i] == '\0')
{
break;
}
i++;
}
}
Which to me, it even copies the \0 from source to destination.
And I have also seen this version:
// Move the assignment into the test
void strcpy2(char dest[], const char source[])
{
int i = 0;
while ((dest[i] = source[i]) != '\0')
{
i++;
}
}
Which to me, it will break when trying to assign \0 from source to dest.
What would be the correct option, copying \0 or not?
The code should look like as follows:
char * strcpy(char *strDest, const char *strSrc)
{
assert(strDest!=NULL && strSrc!=NULL);
char *temp = strDest;
while(*strDest++ = *strSrc++); // or while((*strDest++=*strSrc++) != '\0');
return temp;
}
You can NOT delete the second line char *temp = strDest; and directly return strDest. This will cause error for the returned content. For example, it will not return correct value (should be 22) will checking the length of returned char *.
char src_str[] = "C programming language";
char dst_str[100];
printf("dst_str: %d\n", strlen(strcpy(dst_str, src_str)));
Both copy the terminator, thus both are correct.
Note that strcpy2() does the assignment (the copying) first, then the comparison. So it will copy the terminator before realizing it did, and stopping.
Also, note that functions whose names start with str are reserved, so neither of these are actually valid as "user-level" code.
You're wrong. Both copy the \0 (NUL terminator) character. You have to copy the NUL terminator character always or your string will be broken: you'll never know when/where it ends.
Both copy the terminator, thus both are correct.
strcpy2() does the copying first, then the compares. Thus it will copy the terminator and stops.
The functions whose names start with str are reserved, so use any other variables or naming types
It is recommended not to advance the input pointers to the source and destination memory spaces, since the pointers will be used in main right away.
I've mentioned alternate methodical syntax, where in case someone might wonder the code output.
void strcpy1(char * s, char * p)
{
char * temp1 = s;
char * temp2 = p;
while(*temp1 != '\0')
{
*temp2 = *temp1;
temp1++;
temp2++;
}
*temp2 = '\0';
}
void main()
{
char * a = "Hello";
char b[10];
strcpy1(a,b);
printf("%s", b);
return 0;
}
Both strcpy1() and strcpy2() does the same. Both copy the NUL character to the end of the destination array.
Here is full implementation. You do not have to consider the \0 at the end in the first string, it will be copied automatically from the second string as per logic
//str copy function self made
char *strcpynew(char *d, char *s){
char *saved = d;
while ((*d++ = *s++) != '\0');
return saved; //returning starting address of s1
}
//default function that is run by C everytime
int main(){
//FOR STRCPY
char s1[] = "rahul"; //initializing strings
char s2[] = "arora"; //initializing strings
strcpynew(s1, s2);
printf("strcpy: %s\n", s1); //updated string after strcpy
}
You can use this code, the simpler the better !
Inside while() we copy char by char and moving pointer to the next. When the last char \0 will pass and copy while receive 0 and stop.
void StrCopy( char* _dst, const char* _src )
{
while((*_dst++ = *_src++));
}
char * strcpy(char *strDest, const char *strSrc)
{
assert(strDest!=NULL && strSrc!=NULL);
assert(strSrc + strlen(strSrc) < d || strSrc > strDest); // see note
char *temp = strDest;
while(*strDest++ = *strSrc++)
;
return temp;
}
// without the check on line 4, the new string overwrites the old including the null deliminator, causing the copy unable to stop.
Both copy the '\0'. That's what you have to do if you want to fully emulate the original strcpy