I'm trying to copy a string into a struct, but it doesn't display anything. Can you help me figure it out where the problem is?
typedef struct{
long tipo;
char *buffer;
}msg;
msg mess;
strcpy(mess.buffer,"hello");
printf("%s\n",mess.buffer);
Observing the strcpy declaration
char * strcpy ( char * destination, const char * source );
We notice that it copies the chars from source and store them in destination. But note that it's not specified the length of destination. So it may cause problems if the destination is:
Smaller than the source (Overflow)
Not allocated to some space in the memory (Segmentation Fault)
It's because strcpy function tries to copy char by char until it gets to the end of the 'string'. See how it should look like:
char *strcpy(char *destination , const char *source ){
char *saved = destination;
while (*source){ // while is not NULL
*destination++ = *source++; // Pointer operation
}
*destination = 0; // last position is set to 0 (which is NULL, end of string)
return saved;
}
So when you perform strcpy(mess.buffer,"hello") you can't actually find mess.buffer++ because there's no next memory block since you did not allocated sequential memory. Thus, Segmentation Fault happens.
Finally, you could do:
/* Note that "hello" occupies 6 char spaces: 'h', 'e', 'l', 'l', 'o', '\0' */
int mySize = 10;
mess.buffer = malloc(mySize * sizeof(char));
strcpy(mess.buffer, "hello") // 10 > 6 so OK
Either assign the string directly (note that you will no long be able to modify this string):
msg mess = {.buffer= "hello"};
or use malloc and memcpy function from libc which will perform a memory allocation and copy the bytes of your string to your char pointer for you:
if (!(mess.buffptr = malloc(sizeof(char) * (strlen(s) + 1))))
return 1;
memcpy(mess.buffptr, s, strlen(s));
But I think that what you are looking for is rather to use char buffer[128] instead of a char pointer, see the following example:
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct{
long tipo;
char buffer[128];
char *buffptr; // remove if not needed
} msg;
int main(){
char *s = "hello";
msg mess = {.buffer= "hello"};
mess.buffer[1] = 'a';
printf("'%s' assigned at struct initialization\n",mess.buffer);
(void)mess.buffer;
strcpy(mess.buffer,"hello");
printf("'%s' char array strcpy\n",mess.buffer);
int len = strlen(s) + 1; // to account for '\0'
if (!(mess.buffptr = malloc(sizeof(char) * len)))
return 1;
if (len <= sizeof(mess.buffer))
memcpy(mess.buffptr, s, len);
printf("'%s' char ptr malloced\n",mess.buffptr);
return 0;
}
You can read more about the different between a char pointer and a char array here
Related
Why this works:
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char st[] = "Hello";
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
And this doesn't:
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char*st = "Hello";
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
In first I initialized my string using:
char st[]="Hello"; (using array)
And in latter I used:
char*st="Hello"; (using pointer)
I'm kind of getting confused between these 2 initialization types, what's the key difference between declaring a string by using char st[]="Hello"; and by using char*st = "Hello";.
With char st[] = "Hello";, st[] is a modifiable array of characters. The call slice(st, 1, 6); takes the array st and converts to a pointer to the first element of the array. slice() then receives that pointer, a pointer to modifiable characters.
With char *st = "Hello";, st is a pointer that points to a string literal "Hello". With the call slice(st, 1, 6);, the function receives a copy of the pointer - a pointer to the string literal. Inside slice(), code st[i] = ... is attempting to modify a string literal, that is undefined behavior (UB). It might work, it might fail, it might work today and fail tomorrow - it is not defined.
Do not attempt to modify a string literal.
... passing strings to a function ...
In both cases, code does not pass a string to slice(), but a pointer to a string. Knowing that subtle distinction helps in understanding what is truly happening.
This is an artifact of old syntax in C:
char * s = "Hello world!";
is a non-const character pointer to const memory. It is still permitted by syntax, but the string is still not a mutable object. To be pedantic it should really be written as:
const char * s = "Hello world!";
In contrast:
char s[] = "Hello world!";
allocates a local (on the stack), mutable array and copies the string data to it (from wherever the non-mutable copy is stored in memory). Your function can then do as it likes to your local copy of the string.
The type char [] is different from the type char* (char* is a variable - int. but char[] is an array which is not a variable). However, an array name can be used as a pointer to the array.
So we can say that st[] is technically similar to *str .
the problem in the 2nd version of your code
If you have read-only strings then you can use const char* st = "hello"; or simply char* st = "hello"; . So the string is most probably be stored in a read-only memory location and you'll not be able to modify it.
However, if you want to be able to modify it, use the malloc function:
char *st= (char*) malloc(n*sizeof(char)); /* n-The initial size that you need */
// ...
free(st);
**So to allocate memory for st, count the characters ("hello"-strlen(st)=5) and add 1 for this terminating null character , and functions like scanf and strcpy will add the null character;
so the code becomes :
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char *st =malloc(6*sizeof(char)) ;
const char *cpy="hello";
strcpy(st, cpy); /* copies the string pointed by cpy (including the null character) to the st. */
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
you can fill your string also by a for loop or by scanf() .
in the case of a large allocation you must end your code with free(st);
I have written following c code to update the char array rb but it is printing garbage value
#include <stdio.h>
void update(char* buff){
char word[] = "HII_O";
buff = word;
return;
}
int main(){
char rb[6];
update(rb);
rb[5] = '\0';
printf("[%s]\n",rb);
return 0;
}
The restriction is we can't use any other library. So how to solve this
Within the function update the parameter buff is a local variable of the function that will not be alive after exiting the function.
You can imagine the function call the following way
update( rb );
//...
void update( /*char* buff*/){
char *buff = rb;
char word[] = "HII_O";
buff = word;
return;
}
As you see the original array was not changed.
That is at first the pointer buff was initialized by the address of the first element of the source array rb.
char *buff = rb;
and then this pointer was reassigned with the address of the first element of the local character array word
buff = word;
What you need is to copy characters of the string literal "HII_O" into the source array rb using standard string function strcpy or strncpy.
For example
#include <string.h>
#include <stdio.h>
void update(char* buff){
strcpy( buff, "HII_O" );
}
int main(){
char rb[6];
update(rb);
printf("[%s]\n",rb);
return 0;
}
As you cannot use any library function, just do de copying cell by cell, change
void update( /*char* buff*/){
char *buff = rb;
char word[] = "HII_O";
buff = word;
return;
}
(you cannot assign arrays as a whole in C)
into:
void update(char *buff) {
char *word = "HII_O";
int index;
/* copy characters, one by one, until character is '\0' */
for (index = 0; word[index] != '\0'; index = index + 1) {
buff[index] = word[index];
}
/* index ended pointing to the next character, so we can
* do the next assignment. */
buff[index] = '\0'; /* ...and copy also the '\0' */
}
buff is a local variable to the function. It is initialized to point to the first element of the rb array in main but changes to buff will not change the rb array. So
buff = word;
makes buff point to the string literal "HII_O" but there is no change to the rb array.
The normal solution would be
void update(char* buff){
strcpy(buff, "HII_O");
}
However, you write ...
The restriction is we can't use any other library.
Well, in order to set a fixed value like your code does, you don't need any library function.
You don't any need other variables, string literals, etc.
Just simple character assignments like:
void update(char* buff){
buff[0] = 'H';
buff[1] = 'I';
buff[2] = 'I';
buff[3] = '_';
buff[4] = 'O';
buff[5] = '\0';
}
int main(){
char rb[6];
update(rb);
printf("[%s]\n",rb);
return 0;
}
This is my code
char function(char *dst)
{
int i;
char *arr;
i = 0;
while(dst[i] != '\0')
{
arr[i] = dst[i];
i++;
}
dst[i] != '\0'
return(arr);
}
int main(void)
{
char a[] ="asdf"
printf("%s", function(a);
}
I want to copy *dst to empty *arr but my code didn't work.
I can't understand.
How can I copy array without inner function in C(ex_strcpy, memspy....)
Thank you
Apart from missing ; and making sure that the string being passed to the function is always a '\0' terminated one ( else the program will run into side effects strcpy causes ). and returning char* instead of char, you missed allocating memory for arr
// return char * instead of char
char* function(char *dst)
{
// Note - sizeof(dst) wont work
// Neither does sizeof(dst)/sizeof(char)
// allocate one extra for '\0'
size_t size_to_alloc = (strlen(dst) + 1) * (sizeof *arr);
char *arr = malloc( size_to_alloc );
char *p = arr;
for ( ; *dst ; p++, dst++)
*p = *dst;
*p = '\0';
return(arr);
}
If you want to dynamically copy an array, you'll need to allocate memory for the char array using malloc or other equivalent. Make sure you free the memory once you're done with it. I would suggest reading some posts on malloc and allocating memory in c.
This is probably a good place to start.
https://www.geeksforgeeks.org/dynamic-memory-allocation-in-c-using-malloc-calloc-free-and-realloc/
#include <stdio.h>
#include <stdlib.h>
char* function(char *dst, size_t length) {
int i;
// Allocating the memory needed for the char array.
char *arr = (char*) malloc (sizeof(char) * length);
i = 0;
while(dst[i] != '\0') {
arr[i] = dst[i];
i++;
}
arr[length - 1] = '\0';
return(arr);
}
int main(void) {
char a[] ="asdf";
// Getting length of the array
size_t length = sizeof(a) / sizeof(a[0]);
char* val = function(a, length);
printf("%s", val);
free(val);
}
You are missing the memory allocation and basically attempting to recode strdup. See below:
char *ft_strdup(const char *src)
{
char *dst;
int len;
len = 0;
while (src[len]) // no inner function
++len;
if (!(dst = malloc(sizeof(char) * (len + 1)))) // need 1 extra char to NULL terminate.
return NULL;
dst[len] = '\0';
while (--len > -1)
dst[len] = src[len];
return dst;
}
Note that it makes sense to code your own version of strdup and include it in your program library as this function is not part of the C Standard.
If there is a possibility of copying strings without using c functions, perhaps it can be done by doing what c functions do.
it may be interesting to see what strcpy does:
https://code.woboq.org/userspace/glibc/string/strcpy.c.html
char *
STRCPY (char *dest, const char *src)
{
return memcpy (dest, src, strlen (src) + 1);
}
infact it uses memcpy: https://code.woboq.org/gcc/libgcc/memcpy.c.html
and here the magic...
void *
memcpy (void *dest, const void *src, size_t len)
{
char *d = dest;
const char *s = src;
while (len--)
*d++ = *s++;
return dest;
}
and strlen: https://code.woboq.org/userspace/glibc/string/strlen.c.html
You can use memcpy() to copy memory directly, like in Memcpy, string and terminator and https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html In C any string has to be terminated by \0 (sentinel value)
#include<stdio.h>
#include<string.h>
int main()
{
char source[] = "World";
char destination[] = "Hello ";
/* Printing destination string before memcpy */
printf("Original String: %s\n", destination);
/* Copies contents of source to destination */
memcpy (destination, source, sizeof(source));
/* Printing destination string after memcpy */
printf("Modified String: %s\n", destination);
return 0;
}
source : https://www.educative.io/edpresso/c-copying-data-using-the-memcpy-function-in-c
I have following method
static void setName(const char* str, char buf[16])
{
int sz = MIN(strlen(str), 16);
for (int i = 0; i < sz; i++) buf[i] = str[i];
buf[sz] = 0;
}
int main()
{
const char* string1 = "I am getting bug for this long string greater than 16 lenght);
char mbuf[16];
setName(string,mybuf)
// if I use buf in my code it is leading to spurious characters since length is greater than 16 .
Please let me know what is the correct way to code above if the restriction for buf length is 16 in method static void setName(const char* str, char buf[16])
When passing an array as argument, array decays into the pointer of FIRST element of array. One must define a rule, to let the method know the number of elements.
You declare char mbuf[16], you pass it to setName(), setName() will not get char[], but will get char* instead.
So, the declaration should be
static void setName(const char* str, char* buf)
Next, char mbuf[16] can only store 15 chars, because the last char has to be 'null terminator', which is '\0'. Otherwise, the following situation will occur:
// if I use buf in my code it is leading to spurious characters since length is greater than 16 .
Perhaps this will help you understand:
char str[] = "foobar"; // = {'f','o','o','b','a','r','\0'};
So the code should be
static void setName(const char* str, char* buf)
{
int sz = MIN(strlen(str), 15); // not 16
for (int i = 0; i < sz; i++) buf[i] = str[i];
buf[sz] = '\0'; // assert that you're assigning 'null terminator'
}
Also, I would recommend you not to reinvent the wheel, why don't use strncpy instead?
char mbuf[16];
strncpy(mbuf, "12345678901234567890", 15);
The following code passes the size of the memory allocated to the buffer, to the setName function.
That way the setName function can ensure that it does not write outside the allocated memory.
Inside the function either a for loop or strncpy can be used. Both will be controlled by the size parameter sz and both will require that a null terminator character is placed after the copied characters. Again, sz will ensure that the null terminator is written within the memory allocated to the buffer.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void setName(const char *str, char *buf, int sz);
int main()
{
const int a_sz = 16;
char* string = "This bit is OK!! but any more than 15 characters are dropped";
/* allocate memory for a buffer & test successful allocation*/
char *mbuf = malloc(a_sz);
if (mbuf == NULL) {
printf("Out of memory!\n");
return(1);
}
/* call function and pass size of buffer */
setName(string, mbuf, a_sz);
/* print resulting buffer contents */
printf("%s\n", mbuf); // printed: This bit is OK!
/* free the memory allocated to the buffer */
free(mbuf);
return(0);
}
static void setName(const char *str, char *buf, int sz)
{
int i;
/* size of string or max 15 */
if (strlen(str) > sz - 1) {
sz--;
} else {
sz = strlen(str);
}
/* copy a maximum of 15 characters into buffer (0 to 14) */
for (i = 0; i < sz; i++) buf[i] = str[i];
/* null terminate the string - won't be more than buf[15]) */
buf[i] = '\0';
}
Changing one value const int a_sz allows different numbers of characters to be copied. There is no 'hard coding' of the size in the function, so reducing the risk of errors if the code is modified later on.
I replaced MIN with a simple if ... else structure so that I could test the code.
If we use for example:
char* strs[2];
strs[1] = "Hello";
strs[2] = "World!";
strcat(strs[1],strs[2]);
Then an access violation comes up (Access violation writing location 0x0028CC75).
So why use const char *strs[2]; since the strs1[1], strs1[2] cannot be changed?
// string literals are non-writeable so const is appropriate here
const char* strs[2] = {"Hello", "World!"};
// let's create a target buffer with sufficient space
char buffer[20];
// copy the first string there
strcpy(buffer, strs[0]);
// add the second string there
strcat(buffer, strs[1]);
Two sources of access violation in your case
String literals are read only and writing to them is undefined behavior
In c arrays are 0 index based, so strs[2] does not exist, only strs[0] and strs[1].
Using const prevents you from accidentally modifying them, but it does not forbid you.
Arrays are modifiable though,
#include <stdio.h>
#include <string.h>
int
main(void)
{
char strs[2][11] = {"Hello", "World"};
strcat(strs[0], strs[1]);
return 0;
}
the above works as you expected it.
Here it is how you would do it correctly with dynamic allocation
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *
autostrcat(const char *const head, const char *const tail)
{
char *result;
size_t headlen;
size_t taillen;
if ((head == NULL) || (tail == NULL))
return NULL;
headlen = strlen(head);
taillen = strlen(tail);
result = malloc(1 + headlen + taillen);
if (result == NULL)
return NULL;
memcpy(result, head, headlen);
memcpy(&result[headlen], tail, taillen);
result[headlen + taillen] = '\0';
return result;
}
int
main(void)
{
const char *strs[2] = {"Hello", "World"};
char *result = autostrcat(strs[0], strs[1]);
if (result != NULL)
printf("%s\n", result);
free(result);
return 0;
}
Since you used strlen() you know what the lengths of the strings are, so using strcat() would be unecessarily expensive because it would again figure out the length of the first string as strlen() does.
Wow. So much wrong.
Arrays are 0 based, not 1 based in C.
The strings are based in program space, most likely, so aren't writeable.
you should create a buffer, and then fill it.
char* concat = (char *) _alloca(strlen(strs[0]) + strlen(strs[1])+1);
strcpy(concat, strs[0]);
strcat(concat, strs[1]);