Strcpy thru array subscribed - c

In the Ritchie/Kernighan book, they show a few ways how to create a self made strcpy function, one of them is with using array subscribed instead of char pointers , but when I try this method and run the code it only gives me the second word in this case "world" and not the word "hello"
any clue?
#include <stdio.h>
void xstrcpy(char *a, char *b)
{
int i = 0;
while((a[i] = b[i]) != '\0')
{
i++;
}
}
int main()
{
char name[20] = "hello";
char names[20] = "world";
xstrcpy(names, name);
printf("%s\n", names);
}

Your function overwrites a with the content of b. You could call as like this:
xstrcpy(names + strlen(names), name);
Or you could implement concatenation. Require caller to pass in a sufficiently large string array (dest). Then find the end (end) of the string and copy src to dest. Using the pointers passed in, but you could also use separate indices into dest and src:
#include <stdio.h>
#include <string.h>
// require caller to pass in a dest array large enough for a copy of src
char *xstrcat(char *dest, const char *src) {
char *end = strchr(dest, '\0');
while(*end++ = *src++);
return dest;
}
int main() {
char dest[sizeof("hello") + sizeof("world") - 1] = "hello";
char src[] = "world";
xstrcat(dest, src);
printf("%s\n", dest);
return 0;
}

Related

How to copy char array in C without inner function

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

unite two strings by copying one by one the characters of the second at the end of the first

this program it suppose to print Hello World but guess what exited, segmentation fault why is that happening ?
#include <stdio.h>
#include <string.h>
char f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char*str1 = "hello ";
char*str2 = "world!";
str1=f(str1, str2);
printf("%s", str1);
return 0;
}
You are not allowed to modify string literals. Use arrays with enough elements instead for strings to be modified.
Also assigning the return value of f to str1 is a bad idea because no return statement is executed in the function f and using its return value invokes undefined behavior. The return type should be changed to void if you are not going to return anything.
#include <stdio.h>
#include <string.h>
void f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char str1[16] = "hello ";
char*str2 = "world!";
f(str1, str2);
printf("%s", str1);
return 0;
}
First of all, this:
char*str1 = "hello ";
is a pointer to constant data, which means that you can't change the string "hello "
This is a constant pointer to variable data:
char str1[] = "hello ";
Which means that str1 always points to the same address in memory, but you can modify the content of that chunk of memory.
However str1 will have a fixed size of 7 characters (don't forget to count \0), so you can't append another string to it.
You could define a size #define SIZE 20 large enough to store both strings and declare
char str1[SIZE] = "hello ";
Or you could declare str1 as a VLA (variable length array) after having declared the string to append:
char*str2 = "world!";
char str1[strlen("hello ")+strlen(str2)+1] = "hello ";
Where the +1 is for \0.
Is it important that you copy characters one by one?
Because if it's not you can just copy one string to another like this.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char str1[] = "hello ";
char str2[] = "world!";
char *result = malloc(strlen(str1) + strlen(str2) + 1);
strcpy(result, str1);
strcat(result, str2);
printf("%s", result);
return 0;
}
First you are not allowed to change a constant string, that is undefined behaviour.
Secondly your f function has no return statement and thus returns random data, making the str1 variable in main point to random memory. Using it then also has undefined behaviour.
To fix it you should allocate new memory and concatenate the string into that
char* f(const char *s1, const char *s2)
{
char *s = malloc(strlen(s1) + strlen(s2) +1);
if (s) {
strcpy(s, s1);
strcat(s, s2);
}
return s;
}
The extra one byte allocated is for the terminating zero.
Both arguments are const as there is no reason to modify them, which allows both arguments to be literal strings.
For starters you may not change string literals (in this case the string literal pointed to by the pointer str1).
char*str1 = "hello ";
char*str2 = "world!";
Any attempt to change a string literal results in undefined behavior.
You need to allocate a character array large enough to store the result string with the appended string literal pointed to by the pointer str2.
Secondly there is already the standard C function strcat that performs the required task. If you have to write such a function yourself then it seems you should not use any string function as for example strlen.
And the return type char of your function does not make a sense. And moreover actually your function returns nothing.
So this assignment
str1=f(str1, str2);
results in undefined behavior.
The function and the program in whole can be written the following way without using standard string functions.
#include <stdio.h>
char * f( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) );
return s1;
}
int main(void)
{
char s1[14] = "Hello ";
char *s2 = "World!";
puts( f( s1, s2 ) );
return 0;
}
The program output is
Hello World!
Pay attention to that the second function parameter shall have the qualifier const because the pointed string is not changed within the function. And the function return type should be char * that is the function should return the result string.

Concatenating strings without buffers

Is there a way to concatenate strings without pre-allocating a buffer?
Consider the following:
int main()
{
char buf1[] = "world!";
char buf2[100] = "hello ";
char * p = "hello ";
// printf("%s", strcat(p, buf1)); // UB
printf("%s", strcat(buf2, buf1)); // correct way to use strcat
return 0;
}
If I have a pointer that I want as prefix for a string, must I first copy it to a buffer and then strcat() it? Is there any function that does that implicitly?
The only options I thought of were strcat(), and sprintf(), and both require a buffer.
I need this for a function that expects one string, and I hoped for something close to the Python str1 + str2 syntax
Well, it's not standard C so not very portable, but on GNU libc systems you can use asprintf().
int main(void)
{
const char buf1[] = "world!";
const char * const p = "hello ";
char *s;
if (asprintf(&s, "%s%s", p, buf1) > 0 && s != NULL)
{
puts(s);
free(s);
}
return 0;
}
When compiled and run on a compliant system, this prints
hello world!
I you really want to use C, then you need to use buffers. In C++ or Python you can use constructors and operators that will hide the work for you, but in C you have to do things for yourself. You might create a little helper function if you want to make your code easier, but watch out for memory leaks and threading:
#include "stdlib.h"
#include "string.h"
#include "stdio.h"
const char * strconcat(const char *p1, const char *p2)
{
static __thread char buffer[2048];
snprintf(buffer, 2048, "%s%s", p1, p2);
return buffer;
}
int main(int argc, char** argv)
{
const char *p1 = "hello ";
const char *p2 = "world!";
printf("%s\n", strconcat(p1, p2));
}
This example will work as long as the resulting string does not exceed 2048 characters; otherwise the resulting string will be truncated.
This is of course only one example of helper functions you could create.
Note that the above example returns a const char * which you cannot edit. If you want to further edit the string, you need to create a helper function which allocates a buffer, but then you need to manage your memory!
The most effective way to do this in run-time would be to call malloc and allocate room for a new string, then copy everything there. This is most likely what Python does behind the lines - though it will have a string type.
The disadvantage of doing this outside an ADT/class, is that you have to do the clean-up manually.
Using malloc + copy is however far faster than any *printf, it is thread safe and the same function can be re-used again. Example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* strdog (const char* s1, const char* s2)
{
size_t size1 = strlen(s1);
size_t size2 = strlen(s2);
char* result = malloc(size1 + size2 + 1);
if(result == NULL)
{
exit(EXIT_FAILURE);
}
memcpy(result, s1, size1);
memcpy(result+size1, s2, size2);
result[size1 + size2] = '\0';
return result;
}
inline void cleandog (char* s)
{
free(s);
}
int main (void)
{
char s1[] = "hello ";
char s2[] = "world";
char* str = strdog(s1, s2);
puts(str);
cleandog(str);
}
Note however that C supports compile-time concatenation. So if you are only using string literals, you should do something like this:
#define HELLO "hello "
#define WORLD "world"
...
const char* str = HELLO WORLD;
puts(str);
This is of course the superior version of them all, but only works with compile-time string literals.

Why use const char *prt1 when we can't change the containing of the pointer

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]);

simple strcat implementation with pointers

so I was practicing writing c code with pointers using the K&R. For one problem with strcat function, I couldn't find out what was wrong with my code, which according to Visual Studio, returned the destination string unchanged after the strcat function. Any suggestion is appreciated!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int strcat(char* s, char* t);
int main(void)
{
char *s="hello ", *t="world";
strcat(s,t);
printf("%s",s);
return 0;
}
int strcat(char* s,char* t)
{
int i;
i=strlen(s)+strlen(t);
s=(char*) malloc(i);
while(*s!='\0')
s++;
while('\0'!=(*s++=*t++))
;
return 0;
}
I'm pretty sure that strcat returns a char* in the real implementation (holding the original value of the first string).
strcat is not supposed to alter the first parameter's address, so you shouldn't call malloc.
Point #2 means that you need to declare char *s as char s[20] in main (where 20 is some arbitrary number big enough to hold the whole string).
If you really want to alter the value of the an input parameter you will need to pass the address of the value - so it would need to be strcat(char **s, ...) in the function declaration/definition, and called with strcat(&s, ...) in main.
1) defining string in this way
char *s="hello "
means that you are defined a literal string. a literal string is saved into read only memory so you can not edit it
you have to define your string as a char array in order to be able to edit it
char s[100] = "hello ";
2) when you define your function in this way
int strcat(char* s,char* t)
you can not change the address of s into the function strcat(). So assigning memory with malloc() into the function will not change the s address when leaving the function
3) change your function strcat to
int strcat(char** s,char* t)
{
int i;
char *u, *v;
i=strlen(*s)+strlen(t);
v = *s;
u=(char*) malloc(i+1);
while(*v!='\0')
*u++ = *v++;
while('\0'!=(*u++=*t++));
*s = u;
return 0;
}
and you call it in the main with:
char *s="hello ", *t="world";
strcat(&s,t);
In
strcat(char* s, char* t)
the 's' is send by value. The value of 's' at call time is copied into the stack then strcat() is call. At the return of strcat the modified version is discard from the stack. So the calling value of 's' is never changed (and you create a memory leak).
Beward, in C every memory cell can be change, even parameters or instructions sections; some changes can be very hard to understand.
Since you are trying to do like the real strcat it's said that the first parameter
The string s1 must have sufficient space to hold the result.
so you don't need to use malloc
char *strcat(char* s, const char* t);
int main(void)
{
char s[15] = {0}; //
char *t = "world"; //const char * so you can't change it
strcpy(s, "Hello ");
strcat(s,t);
printf("%s\n",s);
return (0);
}
char *strcat(char* s, const char* t)
{
int i = 0;
while (s[i] != '\0')
i++;
while (*t != '\0')
s[i++] = *t++;
s[i] = '\0'; //useless because already initialized with 0
return (s);
}
#include<stdio.h>
#include<string.h>
#define LIMIT 100
void strcatt(char*,char*);
main()
{
int i=0;
char s[LIMIT];
char t[LIMIT];
strcpy(s,"hello");
strcpy(t,"world");
strcatt(s,t);
printf("%s",s);
getch();
}
void strcatt(char *s,char *t)
{
while(*s!='\0')
{
s++;
}
*s=' ';
++s;
while(*t!='\0')
{
*s=*t;
s++;
t++;
}
*s=*t;
}
Dear user,
you don't have to complicate things that much. The simpliest code for strcat, using pointers:
void strcat(char *s, char *t) {
while(*s++); /*This will point after the '\0' */
--s; /*So we decrement the pointer to point to '\0' */
while(*s++ = *t++); /*This will copy the '\0' from *t also */
}
Although, this won't give you report about the concatenation's success.
Look at this main() part for the rest of the answer:
int main() {
char s[60] = "Hello ";
char *t = "world!";
strcat(s, t);
printf("%s\n", s);
return 0;
}
The s[60] part is very important, because you can't concatenate an another string to it's end if it doesn't have enough space for that.

Resources