I have a small program in C that repeats a given string. But I cannot figure out why the function parameter needs to have an asterisk for const char *src.
Here is my code...
char *repeat_str(size_t count, const char *src) {
int length = strlen(src);
char* dest = malloc(count * length * sizeof(char));
for (int i = 0; i < count; i++) {
strcpy(dest + i * length, src);
}
return dest;
}
When I delete the asterisk as a test, I receive errors saying the asterisk is expected, but I don't understand the explanation as to why.
Take a look at the formal explanations of the pointer declarators: 6.7.6.1 declarators.
char *src is a C convention which says that src is a char pointer.
In program below it points to the string literal holding 4 characters 123_ and string terminator \0.
The length of the string is 4.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
// `repeat_str` accepts variable count of type size_t and const char * pointer
char *repeat_str(size_t count, const char *src) {
size_t length = strlen(src); // get the length
char* dest = malloc(count * length * sizeof(char) + 1); // you need 1 more character for the `null` termination of the dest string
for (size_t i = 0; i < count; i++) {
strcpy(dest + i * length, src);
}
return dest; // return pointer
}
int main() {
const char *src = "123_"; // pointer declaration
char *p; // pointer declaration
p = repeat_str(3,src);
printf(" %s", p);
return 0;
}
Output:
123_123_123_
Related
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
There is no problem with the code. I have a doubt whether we can concatenate two arrays or not. We learned that we cannot increase the size of an array once it is declared. But the following code seems to be doing that. Can we add elements to the statically created arrays using bellow part?
while(S1[i] = S2[j]) {
i++;
j++;
}
#include<stdio.h>
char* strcatt(char[], char[]);
int main(void) {
char S1[] = "University of Colombo";
char S2[] = "Sri Lanka";
printf("%s\n", strcatt(S1, S2));
return 0;
}
char* strcatt(char S1[], char S2[]) {
int i = 0, j = 0;
while(S1[i]) {
i++;
}
S1[i++] = ' ';
while(S1[i] = S2[j]) {
i++;
j++;
}
return (S1);
}
I get this output :- University of Colombo Sri Lanka
The function itself is correct except it should be updated the following way
char * strcatt( char s1[], const char s2[] )
{
size_t i = 0, j = 0;
while ( s1[i] ) i++;
s1[i++] = ' ';
while ( s1[i] = s2[j] )
{
i++;
j++;
}
return s1;
}
That is the type int of the variables i and j should be changed to the type size_t because the size of an array can be greater than the meximum positive value of an object of the type int.
And the second parameter should be qualified as const because it is not changed by the function. Otherwise at least you will not be able to call the function for a constant character array passed to the function as the second argument even it is not changed in the function.
But nevertheless the program has undefined behavior because the character array S1 has no space to accomodate the string stored in the second array S2.
The program will be valid if the first character array will have at least 32 or more elements
char S1[32] = "University of Colombo";
That is if the size of the array will be equal to or greater than sizeof( "University of Colombo" ) + sizeof( "Sri Lanka" )
Take into account that undefined behavior means everything including even the expected result.:) But it also means that the corresponding code is invalid.
In case of your program there are attempts to write to memory beyond the character array S1.
It occurred such a way that the compiler placed the two arrays immediately one after another in the order S1 and then S2. So in fact the function strcatt overwrited the character array S2 by itself.
But it is not necessary that another compiler will place the arrays in this order and moreover without a gap between the character arrays.
Your call to the function is wrong as you do not have enough space for the second string. Usually such a functions allocate memory themselves or get the buffer as the additional parameter. Below you two versions one allocates the memory, the second one takes the buffer. If the buffer is null it allocates the memory for the new string. You need to free it when not needed
char *strcpyt(char *dest, const char *str)
{
char *result = dest;
if(dest && str)
{
while(*dest++ = *src++);
}
return result;
}
size_t strlent(const char *str)
{
const char *start = str;
size_t length = 0;
if(str)
{
while(*str++);
length = str - start - 1;
}
return length;
}
char *strcatt1(const char *str1, const char *str2)
{
char *result = NULL;
size_t size;
if(str1 && str2)
{
result = malloc((size = strlent(str1)) + strlent(str2) + 1);
if(result)
{
strcpyt(result, str1);
strcpyt(result + size, str2);
}
}
return result;
}
char *strcatt2(char *buff, const char *str1, const char *str2)
{
char *result = buff;
size_t size;
if(str1 && str2)
{
if(!result)
{
result = malloc((size = strlent(str1)) + strlent(str2) + 1);
}
if(result)
{
strcpyt(result, str1);
strcpyt(result + size, str2);
}
}
return result;
}
I'm a bit of a newbie at C, so please bear with me...
I have a function to count char in a string called char strLength, but I have to create a function that uses this function to count the number of characters in a passed string, mallocates a new string with space for a NULL terminator, copies the string and then returns the copy.
Here's what I have:
character counter
int strLength(char* toCount)
{
int count = 0;
while(*toCount != '\0')
{
count++;
toCount++;
}
return count;
}
and here's the beginning of the sought-after function
char* strCopy(char *s)
{
int length = strLength(s);
}
Since you are struggling with malloc, here is how the next line should look:
char* strCopy(char *s)
{
int length = strLength(s);
char *res = malloc(length+1);
// Copy s into res; stop when you reach '\0'
...
return res;
}
You want strdup. However, since I suspect this is a learning exercise:
char *strCopy(const char *src)
{
size_t l = strlen(src) + 1;
char *r = malloc(l);
if (r)
memcpy(r, src, l);
return r;
}
If you are curious how to copy strings yourself, you could replace the memcpy with something like:
char *dst = r;
while (*src)
*dst++ = *src++;
*dst = 0;
However I would suggest using library functions: if not strdup, then malloc + memcpy.
You can use strdup() clib call.
You can write something like:
char* strCopy(char *s) {
int length = strLength(s);
char *rc = (char *)malloc(length + 1);
return rc? strcpy(rc, s) : NULL;
}
I'm trying to write a C function to reverse a passed in C style string (ie char *) and return the char pointer of the reversed string. But when I run this in VS2012, nothing is printed in terminal and "main.exe has stopped working" msg shows up.
#include <stdio.h>
#include <string.h>
char * rrev_str(char * str )
{
char *revd_str=""; //I tried char revd_str []="" error: stack around "revd_str" is corrupted
int i,r;
int str_len=strlen(str);
for (i = str_len-1, r=0; i >=0; i--,r++)
{
revd_str[r]= str[i];
}
return revd_str;
}
int main(int argc, char* argv[])
{
char str1 [] ="STEETS";
char str2 [] ="smile everyday!";
//reverse "chars" in a C string and return it
char * rev_string=rrev_str(str1);
}
The problem here is three fold. First you aren't allocating enough space for the reversed string, and secondly you are returning a pointer to a local variable in rrev_str(), and thirdly you're modifying a string literal. You need to allocate space for revd_str on the heap:
char * rrev_str(char * str )
{
int i,r;
int str_len=strlen(str);
char *revd_str=malloc(str_len + 1);
memset(revd_str, 0, str_len + 1);
for (i = str_len-1, r=0; i >=0; i--,r++)
{
revd_str[r]= str[i];
}
return revd_str;
}
Problem: You are accessing invalid memory address.
revd_str is pointing to literal constant string of length 1 and you are accessing it beyond the length which is invalid.
Solution:
Create char array of require length (statically or dynamically).
Reverse the given string.
Pass 2nd param as destination string
syntax: char * rrev_str(char * src, char *dest);
Reverse the given string
char * rrev_str(char * str )
{
int start = 0;
int end = strlen(str) - 1;
char temp;
for (; start < end; start++ ,end--)
{
temp = str[start];
str[start] = str[end];
str[end] = temp;
}
return str;
}
int main(int argc, char* argv[])
{
char string [] ="smile";
//reverse "chars" in a C string and return it
char * rev_string = rrev_str(string);
printf("%s",rev_string);
}
Pass 2nd param as destination string
char * rrev_str(char * src, char *dest)
{
int srcLength = strlen(src);
int destLength = strlen(dest);
int i;
// Invalid destination string
if (srcLength > destLength)
{
return NULL;
}
dest[srcLength] = '\0';
srcLength--;
for (i=0; srcLength >= 0;i++, srcLength--)
{
dest[i] = src[srcLength];
}
return dest;
}
int main(int argc, char* argv[])
{
char string [] ="smile";
char revString[20];
//reverse "chars" in a C string and return it
char * rev_string = rrev_str(string, revString);
printf("%s",rev_string);
}
What! you are doing..
char *revd_str=""; // Creating String Literal which can't be modified because they are read only
char *revd_str[]=""; // Creating Char Array of Size Zero.
So Solution are
Either take reference of your string
char *revd_str = strdup(str);
Or create dynamic char array
char *revd_str = (char*) malloc (strlen(str)+1);
your program will run fine. logic is incorrect for reversing so modify it. A sample solution is given below
char * rrev_str(char * str )
{
char *revd_str=strdup(str);
int i; // no need for extra 'int r'
int str_len=strlen(str);
for (i = 0; i < str_len/2; i++)
{
char temp = revd_str[i];
revd_str[i]= revd_str[str_len - 1 -i];
revd_str[str_len - 1 -i] = temp;
}
return revd_str;
}
Using pointer arithmetic, it's possible to assign characters from one array to another. My question is, how does one do it given arbitrary start and stop points?
int main(void)
{
char string1[] = "something"; //[s][o][m][e][t][h][i][n][g][\0]
int start = 2, count = 3;
char string2[10] = {0};
char *ptr1 = &string1[start];
char *ptr2 = string2;
while (*ptr2++ = *ptr1++) { } //but stop after 3 elements???
printf("%s",&string2);
}
There's some kind of pointer arithmetic I'm missing to count/test the quantity of elements in a particular array. I do NOT want to declare an integral to count the loop! I want to do it all using pointers. Thanks!
When you write ptr1++;, it is equivalent to ptr1 = ptr1 + 1;. Adding an integer to a pointer moves the memory location of the pointer by the size (in bytes) of the type being pointed to. If ptr1 is a char pointer with value 0x5678 then incrementing it by one makes it 0x5679, because sizeof(char) == 1. But if ptr1 was a Foo *, and sizeof(Foo) == 12, then incrementing the pointer would make its value 0x5684.
If you want to point to an element that is 3 elements away from an element you already have a pointer to, you just add 3 to that pointer. In your question, you wrote:
char *ptr1 = &string1[start]; // array notation
Which is the same thing as:
char *ptr1 = string1 + start; // pointer arithmetic
You could rewrite as follows:
int main(void)
{
char string1[] = "something"; //[s][o][m][e][t][h][i][n][g][\0]
int start = 2, count = 3;
char string2[10] = {0};
// Ensure there is enough room to copy the substring
// and a terminating null character.
assert(count < sizeof(string2));
// Set pointers to the beginning and end of the substring.
const char *from = string1 + start;
const char *end = from + count;
// Set a pointer to the destination.
char *to = string2;
// Copy the indicated characters from the substring,
// possibly stopping early if the end of the substring
// is reached before count characters have been copied.
while (from < end && *from)
{
*to++ = *from++
}
// Ensure the destination string is null terminated
*to = '\0';
printf("%s",&string2);
}
Using const and meaningful variable names (from, to, or src, dst, instead of ptr1, ptr2) helps you avoid mistakes. Using assert and ensuring the string is null-terminated helps you avoid having to debug segfaults and other weirdness. In this case the destination buffer is already zeroed, but when you copy parts of this code to use in another program it may not be.
#include <stdio.h>
int main(void)
{
char string1[] = "something"; //[s][o][m][e][t][h][i][n][g][\0]
int start = 2, count = 3;
char string2[10] = {0};
char *ptr1 = &string1[start];
char *stop = ptr1 + count;
char *ptr2 = string2;
while ((ptr1 < stop) && (*ptr2++ = *ptr1++));
printf("%s",string2);
return 0;
}
I usually use a specific set of variable names in these situations, called:
src - source
dst - destination
end - the end of either the source (used here) or the destination
So:
int main(void)
{
char string1[] = "something";
int start = 2;
int count = 3;
char string2[10] = {0};
const char *src = &string1[start];
const char *end = &string1[start+count];
char *dst = string2;
assert(count < sizeof(string2);
while (src < end)
*dst++ = *src++;
*dst = '\0'; // Null-terminate copied string!
printf("%s",&string2);
return(0);
}
Or, more plausibly, packaged as a function:
char *copy_substr(char *dst, const char *str, size_t start, size_t len)
{
const char *src = str + start;
const char *end = src + len;
while (src < end)
*dst++ = *src++;
*dst = '\0';
return(dst);
}
int main(void)
{
char string1[] = "something";
char *end;
char string2[10] = {0};
end = copy_substr(string2, string1, 2, 3);
printf("%s",&string2);
return(0);
}
The function returns a pointer to the end of the string which is aconventional and doesn't provide a marked benefit in the example, but which does have some merits when you are building a string piecemeal:
struct substr
{
const char *str;
size_t off;
size_t len;
};
static struct substr list[] =
{
{ "abcdefghijklmnopqrstuvwxyz", 2, 5 },
...
{ "abcdefghijklmnopqrstuvwxyz", 18, 3 },
};
int main(void)
{
char buffer[256];
char *str = buffer;
char *end = buffer + sizeof(buffer) - 1;
size_t i;
for (i = 0; i < 5; i++)
{
if (str + list[i].len >= end)
break;
str = copy_substr(str, list[i].str, list[i].off, list[i].len);
}
printf("%s\n", buffer);
return(0);
}
The main point is that the return value - a pointer to the NUL at the end of the string - is what you need for string concatenation operations. (In this example, with strings that have known lengths, you could survive without this return value without needing to use strlen() or strcat() repeatedly; in contexts where the called function copies an amount of data that cannot be determined by the calling routine, the pointer to the end is even more useful.)
In order to get the size (i.e. number of elements) in a static array, you would usually do
sizeof(string1) / sizeof(*string1)
which will divide the size (in bytes) of the array by the size (in bytes) of each element, thus giving you the number of elements in the array.
But as you're obviously trying to implement a strcpy clone, you could simply break the loop if the source character *ptr1 is '\0' (C strings are zero-terminated). If you only want to copy N characters, you could break if ptr1 >= string1 + start + count.