I'm very new to C, I'm getting stuck using the strncpy function.\
Here's an example of what I'm working with:
int main()
{
const char *s = "how";
struct test {
char *name;
};
struct test *t1 = malloc(sizeof(struct test));
strncpy(t1->name, s, sizeof(*s));
t1->name[NAMESIZE] = '\0';
printf("%s\n", t1->name);
}
I have a const char *, I need to set the "name" value of test to the const char. I'm having a really tough time figuring this out. Is this even the correct approach?
Thank you very much!
Well, you allocate the structure, but not the string inside the structure. You need to do that before you copy to it. Even when you do, you will probably overwrite unallocated memory when you attempt to set the string terminator.
And, due to a hight intake ow wine, I just noticed you actually only copy one character, but it's still undefined behavior.
Let's take this one step at a time:
struct test *t1 = malloc(sizeof(struct test));
this allocates space for a struct test; enough space for the pointer name, but not any memory for the pointer to point to. At a minimum, you'll want to do the following:
t1->name = malloc(strlen(s) + 1);
Having done that, you can proceed to copy the string. However, you already computed the length of the string once to allocate the memory; there's no sense in doing it again implicitly by calling strncpy. Instead, do the following:
const size_t len = strlen(s) + 1; // +1 accounts for terminating NUL
t1->name = malloc(len);
memcpy(t1->name, s, len);
In general, try to use this basic pattern; compute the length of strings once when they come into your code, but then use explicit-sized memory buffers and the mem* operations instead of implicit-length strings with str* operations. It is at least as safe (and often safer) and more efficient if done properly.
You might use strncpy if t1->name was a fixed-size array instead (though many people prefer to use strlcpy). That would look like the following:
struct test { char name[MAXSIZE]; };
struct test *t1 = malloc(sizeof *t1);
strncpy(t1->name, s, MAXSIZE - 1);
t1->name[MAXSIZE-1] = 0; // force NUL-termination
Note that the size argument to strncpy should always be the size of the destination, not the source, to avoid writing outside the bounds of the destination buffer.
Without any attempt at completeness or educational direction, here's a version of your code that should work. You can play "spot the difference" and search for an explanation for each one separately on this site.
int main()
{
const char s[] = "how"; // s is an array, const char[4]
struct test{ char name[NAMESIZE]; }; // test::name is an array
struct test * t1 = malloc(sizeof *t1); // DRY
strncpy(t1->name, s, NAMESIZE); // size of the destination
t1->name[NAMESIZE - 1] = '\0'; // because strncpy is evil
printf("%s\n", t1->name);
free(t1); // clean up
}
strncpy() is always wrong
if the result is too long, the target string will not be nul-terminated
if the target is too long (the third argument) , the trailing end will be completely padded with NULs. This will waste a lot of cycles if you have large buffers and short strings.
Instead, you cound use memcpy() or strcpy, (or in your case even strdup() )
int main()
{
const char *s = "how";
struct test {
char *name;
};
struct test *t1
size_t len;
t1 = malloc(sizeof *t1);
#if USE_STRDUP
t1->name = strdup(s);
#else
len = strlen(s);
t1->name = malloc (1+len);
memcpy(t1->name, s, len);
t1->name[len] = '\0';
#endif
printf("%s\n", t1->name);
return 0;
}
Related
I've looked through topics of similar kind, but didn't find a solution for my problem. I've got a struct like
typedef struct {
int number;
char *string;
} mystruct;
//Then define a pointer to the struct:
mystruct *data;
// Allocate memory:
data = malloc(sizeof(mystruct));
//Assign some number, let's say 5:
(*data).number = 5;
//So far ok, works (checked: 5 can be retrieved from the struct somewhere else) but:
strcpy((*data).string = "Hello!");
//This line fails with segmentation fault.
I don't understand why? Can somebody please explain what I'm doing wrong?
As mentioned in the comments, the problem with your attempted strcpy call is that your destination (the string member of your data) isn't a pointer to valid memory. (I am assuming that your invalid syntax, strcpy((*data).string = "Hello!") is a typo, and that your real code has something like strcpy((*data).string, "Hello!") – otherwise, it won't even compile, so you won't get a segmentation fault.)
There are several approaches to fix this, depending on what you actually want to happen. First, as also mentioned in the comments, you can just copy the pointer to the destination, like this1:
data->string = "Hello!";
However, this may not be what you want, because, if the source is not actually a literal, but a modifiable string, then, after that assignment, any changes to the source will also apply to your copy.
If you want a copy of the source data, you will need to allocate sufficient space for it, then call strcpy; like this:
#include <stdlib.h> // For malloc
const char* src = "Hello!";
data->string = malloc(strlen(src) + 1); // Add 1 for the required nul-terminator
strcpy(data->string, src);
However, the strdup function2 does the job of the above malloc and strcpy calls in one fell swoop:
data->string = strdup("Hello!");
In each of the above two cases, be sure to call free(data->string) when you're finished.
1 Note that you can use the "member access through pointer" (->) operator, rather than dereferencing and then using the . operator: data->number = 5 is equivalent to your (*data).number = 5.
2 Some compilers/platforms may not support the strdup function, but it is part of the ISO C Standard from C23
As other users mentioned, you need to allocate space for the string.
I would use a flexible array member and have only one allocation for the struct and string.
typedef struct {
int number;
char string[];
} mystruct;
mystruct *create(const char *str)
{
mystruct *ms = NULL;
if(str)
{
ms = malloc(sizeof(*ms) + strlen(str) + 1);
if(ms)
{
strcpy(ms -> string, str);
ms -> number = 0;
}
}
return ms;
}
int main(void)
{
mystruct *ms = create("Hello");
if(ms)
{
printf("ms -> string = `%s`\n", ms -> string);
}
free(ms);
}
I am not sure to understand this line
strcpy((*data).string = "Hello!");
Do you mean
strcpy((*data).string, "Hello!");
I believe the issue is that your struct contain a pointer char * string that doesn't point to a valid allocated memory.
You can try multiple solutions
Have struct with predefined size
typedef struct {
int number;
char string[100];
} mystruct;
You can allocate memory for the string during the initialization
data = malloc(sizeof(mystruct));
data->string = malloc(sizeof(char) *100));
I am studying for a Data Structures and Algorithms exam. One of the sample questions related to dynamic memory allocation requires you to create a function that passes a string, which takes it at copies it to a user defined char pointer. The question provides the struct body to start off.
I did something like this:
typedef struct smart_string {
char *word;
int length;
} smart_string;
smart_string* create_smart_string(char *str)
{
smart_string *s = (smart_string*)malloc(sizeof(smart_string));
s->length = strlen(str);
s->word = malloc(s->length);
strcpy(s->word, str);
return s;
}
But the answer was this
typedef struct smart_string {
char *word;
int length;
} smart_string;
smart_string *create_smart_string(char *str)
{
smart_string *s = malloc(sizeof(smart_string));
s->length = strlen(str);
s->word = malloc(sizeof(char) * (s->length + 1));
strcpy(s->word, str);
return s;
}
I went on code:blocks and tested them both to see any major differences. As far as I'm aware, their outputs were the same.
I did my code the way it is because I figured if we were to allocate a specific block of memory to s->word, then it should be the same number of bytes as s ->length, because that's the string we want to copy.
However the correct answer below multiplies sizeof(char) (which is just 1 byte), with s->length + 1. Why the need to add 1 to s->length? What's the importance of multiplying s->length by sizeof(char)? What mistakes did I make in my answer that I should look out for?
sizeof(char) == 1 by definition, so that doesn't matter.
You should not cast the result of malloc: Do I cast the result of malloc?
And your only real difference is that strlen returns the length of the string, not including the terminating NUL ('\0') character, so you need to add + 1 to the size of the buffer as in the solution.
If you copy there the string, the terminating character won't be copied (or worse, it will be copied on some other memory), and therefore, any function that deals with strings (unless you use special safety functions such as strscpy) will run through the buffer and past it since they won't find the end. At that point it is undefined behaviour and everything can happen, even working as expected, but can't rely on that.
The reason it is working as expected is because probably the memory just next to the buffer will be 0 and therefore it is being interpreted as the terminating character.
Your answer is incorrect because it doesn't account for the terminating '\0'-character. In C strings are terminated by 0. That's how their length can be determined. A typical implementation of strlen() would look like
size_t strlen(char const *str)
{
for (char const *p = str; *p; ++p); // as long as p doesn't point to 0 increment p
return p - str; // the length of the string is determined by the distance of
} // the '\0'-character to the beginning of the string.
But both "solutions" are fubar, though. Why would one allocate a structure consisting of an int and a pointer on the free-store ("heap")!? smart_string::length being an int is the other wtf.
#include <stddef.h> // size_t
typedef struct smart_string_tag { // *)
char *word;
size_t length;
} smart_string_t;
#include <assert.h> // assert()
#include <string.h> // strlen(), strcpy()
#include <stdlib.h> // malloc()
smart_string_t create_smart_string(char const *str)
{
assert(str); // make sure str isn't NULL
smart_string_t new_smart_string;
new_smart_string.length = strlen(str);
new_smart_string.word = calloc(new_smart_string.length + 1, sizeof *new_smart_string.word);
if(!new_smart_string.word) {
new_smart_string.length = 0;
return new_smart_string;
}
strcpy(new_smart_string.word, str);
return new_smart_string;
}
*) Understanding C Namespaces
I've declared the struct foo like this:
struct foo {
const char* name_lower;
const char* name_caps
//..
};
I dynamically create instances of foo on the heap and want to save a value in the name_lower and name_caps member variable. This is done by the function bar
void bar(foo* entry, const char* str, int delimiter_pos) {
char l[2] = {str[caps_pos-1], '\0'}; // create new string
char c[2] = {str[caps_pos+1], '\0'};
entry->name_lower = &l[0]; // assign these strings the foo instance
entry->name_caps = &c[0];
}
I am worried, because I don't know if this code is going to crash. The temporarily created arrays l and c will be saved on the stack. Once the function terminates the stack will be cleared up and c and l will probably disappear.
Does this mean that the foo instance will lose its names, i.e. its references? If so, how can I solve this problem?
Continuing from the comment, the easiest way to allocate/copy and assign the start address for new blocks of memory for l and c is to use strdup (from string.h):
void bar(foo* entry, const char* str, int delimiter_pos) {
char l[2] = {str[caps_pos-1], '\0'}; // create new string
char c[2] = {str[caps_pos+1], '\0'};
entry->name_lower = strdup (l); // assign these strings the foo instance
entry->name_caps = strdup (c);
}
Don't forget to free the memory allocated to entry->name_lower and entry->name_caps when no longer needed.
You should instead use char *l = (char *)malloc(2 * sizeof(char)); and then initialize it; similarly for char *c. Then set entry->name_lower = l; entry->name_caps = c;
When allocating make sure you check whether the allocation succeeded, i.e. whether malloc returned non-NULL address.
Make sure you free the memory after you don't need it anymore: free(entry->name_lower); free(entry->name_caps);.
It will not lose anything. The pointers in the struct will retain their value, but the content will change and you will eventually get SIGSEGV.
For the char * to persist, you need to allocate it on the heap too.
void bar(foo* entry, const char* str, int delimiter_pos) {
char * l = malloc(2);
char * c = malloc(2);
/* Check l and c for NULLs */
l[0] = str[caps_pos-1];
l[1] = '\0';
c[0] = str[caps_pos+1];
c[1] = '\0';
entry->name_lower = l;
entry->name_caps = c;
}
Remember that you should also free() the struct members when you will no longer need it.
If you have a limit on the length of your strings, you can use char arrays instead of pointers. In your example, all strings have a length of 1. Assuming your strings cannot be longer than that, you can use char[2] instead of char*:
struct foo {
char name_lower[2];
char name_caps[2];
//..
};
void bar(foo* entry, const char* str, int delimiter_pos) {
entry->name_lower[0] = str[caps_pos-1];
entry->name_lower[1] = '\0';
entry->name_caps[0] = str[caps_pos+1];
entry->name_caps[1] = '\0';
}
Historical note:
Because this is so easy to use, people got accustomed to this, and forced artificial limits on string length, leading to buffer overflows. If your strings are not limited, use dynamic allocation instead of char arrays.
I have a character pointer, which has a string assigned to it. And I'm sure that the string is of 8 characters length. (Ex: SHIVA0BS) And it is also a fact that the last two letters are always going to be "BS". But I'm just going to double check it. Now I'd like to take the first 6 characters ("SHIVA0") and append it to something else, say ("SHIVA0NN") - how would I make it possible?
#include<stdio.h>
#include<stdlib.h>
void main()
{
char *ptr, *new;
ptr = "FECI00BS";
strncpy(new,ptr,6);
printf("%s",new);
strcat(new,"NN");
}
The above code is what I wrote. And I'm not sure why it is not working. I understand that my requirement is very trivial, but I tried printfs in between. I was able to find that (ptr+6) printed "BS", so that 6 is the length that I need. But this is still not working. Any help appreciated. I need the output in a string pointer. A new one is fine. But a string pointer.
P.S: Only C code please. No C++.
You didn't allocate memory to hold your new string
char * new = calloc(1, 10); // on heap
or
char new[10]; // on stack
memset(new, 0, sizeof(new)); // zero it
You're not allocating memory for storing the strings.
You need to allocate memory for both *ptr and *new.
The bare minimum would be:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char *ptr, *new;
new = (char*)malloc(sizeof(char) * 9);
new = (char*)malloc(sizeof(char) * 9);
ptr = "FECI00BS";
strncpy(a,ptr,6);
printf("%s",new);
strcat(a,"NN");
printf("%s",new);
}
You need 9 bytes (assuming your platform needs one byte per char) because of the End-Of-Line character, '\0', that needs to be present at the end of strings in order to use some string.h functions or print them correctly.
Also, read on why you need to be careful with strncpy. Depending on your platform, you may have access to some newer, safer alternatives from the C standard.
I think you want:
sprintf(ptr+6, "NN");
That will modify your buffer to convert BS into NN. In this case you can get rid of the new variable.
EDIT
Try this. Notice the char ptr[] instead of char* ptr. By using [] instead of a pointer you are allocating the buffer on the stack. This allows you to write to the buffer.
#include<stdio.h>
#include<stdlib.h>
void main()
{
char ptr[] = "FECI00BS";
sprintf(ptr+6,"NN");
printf(ptr);
}
Just a few simple checks and memcpy().
char *ShivaAppend(char *dest, const char *ptr, const char *suffix) {
size_t len = strlen(ptr);
if (len != 8) {
return NULL;
}
if (strcmp(ptr, "BS") != 0) {
return NULL;
}
len = strlen(suffix);
if (len != 2) {
return NULL;
}
memcpy(dest, ptr, 6);
memcpy(&dest[6], suffix, 2);
return dest;
}
...
char dest[9];
char *p = ShivaAppend(dest, "SHIVA0BS", "NN")
puts(p == NULL ? "fail", p);
I am having trouble concatenating strings in C, without strcat library function. Here is my code
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
char *a1=(char*)malloc(100);
strcpy(a1,"Vivek");
char *b1=(char*)malloc(100);
strcpy(b1,"Ratnavel");
int i;
int len=strlen(a1);
for(i=0;i<strlen(b1);i++)
{
a1[i+len]=b1[i];
}
a1[i+len]='\0';
printf("\n\n A: %s",a1);
return 0;
}
I made corrections to the code. This is working. Now can I do it without strcpy?
Old answer below
You can initialize a string with strcpy, like in your code, or directly when declaring the char array.
char a1[100] = "Vivek";
Other than that, you can do it char-by-char
a1[0] = 'V';
a1[1] = 'i';
// ...
a1[4] = 'k';
a1[5] = '\0';
Or you can write a few lines of code that replace strcpy and make them a function or use directly in your main function.
Old answer
You have
0 1 2 3 4 5 6 7 8 9 ...
a1 [V|i|v|e|k|0|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_]
b1 [R|a|t|n|a|v|e|l|0|_|_|_|_|_|_|_|_|_|_|_|_|_]
and you want
0 1 2 3 4 5 6 7 8 9 ...
a1 [V|i|v|e|k|R|a|t|n|a|v|e|l|0|_|_|_|_|_|_|_|_]
so ...
a1[5] = 'R';
a1[6] = 'a';
// ...
a1[12] = 'l';
a1[13] = '\0';
but with loops and stuff, right? :D
Try this (remember to add missing bits)
for (aindex = 5; aindex < 14; aindex++) {
a1[aindex] = b1[aindex - 5];
}
Now think about the 5 and 14 in the loop above.
What can you replace them with? When you answer this, you have solved the programming problem you have :)
char a1[] = "Vivek";
Will create a char array a1 of size 6. You are trying to stuff it with more characters than it can hold.
If you want to be able to accommodate concatenation "Vivek" and "Ratnavel" you need to have a char array of size atleast 14 (5 + 8 + 1).
In your modified program you are doing:
char *a1=(char*)malloc(100); // 1
a1 = "Vivek"; // 2
1: Will allocate a memory chunk of size 100 bytes, makes a1 point to it.
2: Will make a1 point to the string literal "Vivek". This string literal cannot be modified.
To fix this use strcpy to copy the string into the allocated memory:
char *a1=(char*)malloc(100);
strcpy(a1,"Vivek");
Also the for loop condition i<strlen(b1)-1 will not copy last character from the string, change it to i<strlen(b1)
And
a1[i]='\0';
should be
a1[i + len]='\0';
as the new length of a1 is i+len and you need to have the NUL character at that index.
And don't forget to free your dynamically allocated memory once you are done using it.
You cannot safely write into those arrays, since you have not made sure that enough space is available. If you use malloc() to allocate space, you can't then overwrite the pointer by assigning to string literal. You need to use strcpy() to copy a string into the newly allocated buffers, in that case.
Also, the length of a string in C is computed by the strlen() function, not length() that you're using.
When concatenating, you need to terminate at the proper location, which your code doesn't seem to be doing.
Here's how I would re-implement strcat(), if needed for some reason:
char * my_strcat(char *out, const char *in)
{
char *anchor = out;
size_t olen;
if(out == NULL || in == NULL)
return NULL;
olen = strlen(out);
out += olen;
while(*out++ = *in++)
;
return anchor;
}
Note that this is just as bad as strcat() when it comes to buffer overruns, since it doesn't support limiting the space used in the output, it just assumes that there is enough space available.
Problems:
length isn't a function. strlen is, but you probably shouldn't call it in a loop - b1's length won't change on us, will it? Also, it returns a size_t, which may be the same size as int on your platform but will be unsigned. This can (but usually won't) cause errors, but you should do it right anyway.
a1 only has enough space for the first string, because the compiler doesn't know to allocate extra stack space for the rest of the string since. If you provide an explicit size, like [100], that should be enough for your purposes. If you need robust code that doesn't make assumptions about what is "enough", you should look into malloc and friends, though that may be a lesson for another day.
Your loop stops too early. i < b1_len (assuming you have a variable, b1_len, that was set to the length of b1 before the loop began) would be sufficient - strlen doesn't count the '\0' at the end.
But speaking of counting the '\0' at the end, a slightly more efficient implementation could use sizeof a1 - 1 instead of strlen(a1) in this case, since a1 (and b1) are declared as arrays, not pointers. It's your choice, but remember that sizeof won't work for pointers, so don't get them mixed up.
EDIT: New problems:
char *p = malloc(/*some*/); p = /* something */ is a problem. = with pointers doesn't copy contents, it copies the value, so you're throwing away the old pointer value you got from malloc. To copy the contents of a string into a char * (or a char [] for that matter) you'd need to use strcpy, strncpy, or (my preference) memcpy. (Or just a loop, but that's rather silly. Then again, it may be good practice if you're writing your own strcat.)
Unless you're using C++, I wouldn't cast the return value of malloc, but that's a religious war and we don't need one of those.
If you have strdup, use it. If you don't, here is a working implementation:
char *strdup(const char *c)
{
size_t l = strlen(c);
char *d = malloc(l + 1);
if(d) memcpy(d, c, l + 1);
return d;
}
It is one of the most useful functions not in the C standard library.
You can do it using strcpy() too ;)
char *a = (char *) malloc(100);
char *b = (char *) malloc(100);
strcpy(a, "abc"); // initializes a
strcpy(b, "def"); // and b
strcpy((a + strlen(a)), b); // copy b at end of a
printf("%s\n",a); // will produce: "abcdef"
i think this is an easy one.
#include<stdio.h>
int xstrlen(char *);
void xstrcat(char *,char *,int);
void main()
{
char source[]="Sarker";
char target[30]="Maruf";
int j=xstrlen(target);
xstrcat(target,source,j);
printf("Source String: %s\nTarget String: %s",source,target);
}
int xstrlen(char *s)
{
int len=0;
while(*s!='\0')
{
len++;
s++;
}
return len;
}
void xstrcat(char *t,char *s,int j)
{
while(*t!='\0')
{
*t=*t;
t++;
}
while(*s!='\0')
{
*t=*s;
s++;
t++;
}
}
It is better to factor out your strcat logic to a separate function. If you make use of pointer arithmetic, you don't need the strlen function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* To completely get rid of this,
implement your our strcpy as well */
static void
my_strcat (char* dest, char* src)
{
while (*dest) ++dest;
while (*src) *(dest++) = *(src++);
*dest = 0;
}
int
main()
{
char* a1 = malloc(100);
char* b1 = malloc(100);
strcpy (a1, "Vivek");
strcpy (b1, " Ratnavel");
my_strcat (a1, b1);
printf ("%s\n", a1); /* => Vivek Ratnavel */
free (a1);
free (b1);
return 0;
}