Is repeat string literal possible using 'for' loop in C? - c

I am wondering can pure C do following pseudo code?
for(int i = 0; i < N; i++)
func( Multi("str",i));
I know the feature char *tmp = "str1" "str1" and tried to combine that and macro. But, the only way I come up with is define several macro with different repeat times. My method is bad for concise, are there better method ?
edit:
expect Multi can return "str" * i times
e.g. char *tmp = Multi("str",3); // now tmp is "strstrstr"

Not if you expect to be able to use the run-time value of a variable to control the number of repetitions (unless the range of values of that variable is small and known at compile-time).
Macro expansion and literal string concatenation are done as phases during the compilation, before the executable has been produced. The program doesn't yet exist, and certainly cannot be run. The macro preprocessor only sees a variable as an identifier inside the text of the program.
If you will always use a literal integer, then it is possible to do the expansion with the macro preprocessor, although it does indeed require a lot of macros. There are some macro libraries which can help.
If you know the maximum number of repetitions (and have some runtime mechanism to verify that the limit is not exceeded), you could create a single string literal of the maximum size, perhaps using a macro library as mentioned above. You can then get a string literal containing fewer than this maximum by starting int the middle:
#define Multi(literal, rep) \
(&(REP(MAXREP, literal))[((sizeof literal)-1)*(MAXREP-rep)])
For that to work, MAXREP must be previously #defined as a (smallish) integer constant (not a constant expression).
Here's a complete example program, using BOOST_PP_REPEAT from the Boost preprocessor library to define REP:
#include <stdio.h>
#include <stdlib.h>
#include <boost/preprocessor/repeat.hpp>
#define MAXREP 80
#define REPEATER(z, n, literal) literal
#define REP(n, literal) BOOST_PP_REPEAT(n, REPEATER, literal)
#define Multi(literal, rep) \
(&(REP(MAXREP, literal))[((sizeof literal)-1)*(MAXREP-rep)])
int main(int argc, char** argv) {
int reps = 0;
if (argc > 1) reps = atoi(argv[1]);
if (reps <= 0) reps = MAXREP;
if (reps > MAXREP) {
fprintf(stderr, "Cannot do %d repetitions; maximum is %d\n", reps, MAXREP);
exit(1);
}
for (int i = 0; i < reps; ++i) printf("%s\n", Multi("foo", i));
return 0;
}
Sample run:
$ make rep
cc -O0 -Wall -ggdb -std=c11 -D_XOPEN_SOURCE=700 -mtune=native rep.c -o rep
$ ./rep 5
foo
foofoo
foofoofoo
foofoofoofoo

Perhaps something employing a compound literal (since C99) to form the space needed?
MULTI(some_string_literal, n) is valid until the end of the block. No need to free.
#include <string.h>
char *Multi(char *dest, const char *s, unsigned n) {
size_t len = strlen(s);
char *p = dest;
while (n-- > 0) {
memcpy(p, s, len);
p += len;
}
*p = 0;
return dest;
}
// compound literal v-------------------------------v
#define MULTI(s, n) Multi( (char [(sizeof(s) - 1)*n + 1]){0} , (s), (n))
#include <stdio.h>
int main() {
char *tmp = MULTI("str", 3);
printf("<%s>\n", tmp);
printf("<%s> <%s>\n", MULTI("str", 4), MULTI("str", 5));
printf("%p\n", MULTI("str", 6));
}
Sample output
<strstrstr>
<strstrstrstr> <strstrstrstrstr>
0xffffcb80

One way to implement this is to use strncpy and calloc to copy the original string several times into a new char array
char* repeat(char* orig, size_t times) {
if (times == 0) return calloc(1, sizeof(char)); // is the empty string
else {
size_t orig_length = strlen(orig);
size_t new_length = times * orig_length;
char* new_str = malloc((new_length + 1) * sizeof(char));
for (size_t i = 0; i < times; i++) {
strncpy(&new_str[orig_length * i], orig, orig_length);
}
new_str[new_length] = 0; // setting the null-byte
return new_str;
}
}
This function return always a new string, which needs to be freed with free before the last reference to it is lost or else you will have a memory leak.
This could also be done recursive, but this won't do much for this kind of function.
And this can most likly be optimized, feel free to suggest improvements.

Yes pure C can do a lot my friend, here I have written a function for you
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * strRepeat(char *str, int n) {
int len = strlen(str);
char *repeatedStr = (char *)malloc(len * n + 1);
if(repeatedStr == NULL) {
return NULL;
}
for(int i = 0;i < len * n; i++) {
repeatedStr[i] = str[i % len];
}
repeatedStr[len * n] = '\0';
return repeatedStr;
}
int main(void) {
char *s = strRepeat("str", 7);
printf("%s", s);
//output: strstrstrstrstrstrstr
free(s);
return 0;
}

Related

Using free() corrupts char array data in C

The problem:
I need to malloc a struct to populate a char *[64] array. This array gets corrupted when I free the struct. Specifically the first index. How should I deal with this?
int main(void) {
char *names[64];
uint32_t aCount = 0;
uint32_t count = 0;
vkEnumerateInstanceExtensionProperties(NULL,&count, NULL);
VkExtensionProperties *extension_names = malloc(sizeof(VkExtensionProperties) * count);
vkEnumerateInstanceExtensionProperties(NULL,&count,extension_names);
for(uint32_t i = 0; i < count; i++) {
names[aCount++] = extension_names[i].extensionName;
}
printf("First extension available: %s\n",names[0]);
free(extension_names);
printf("First extension available: %s\n",names[0]);
return 0;}
Here is the result:
Before free()
First extension available: VK_KHR_device_group_creation
After free()
First extension available: ���yUU
You can use strdup to make copies of the strings and solve the "use after free" problem you are having:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define UNUSED(x) \
((void)(x))
#define VK_MAX_EXTENSION_NAME_SIZE 256
typedef struct VkExtensionProperties {
char extensionName[VK_MAX_EXTENSION_NAME_SIZE];
uint32_t specVersion;
} VkExtensionProperties;
void vkEnumerateInstanceExtensionProperties(void *unused,
uint32_t *count, VkExtensionProperties *result) {
UNUSED(unused);
*count = 64;
if (result) {
for (int index = 0; index < *count; index++) {
snprintf(result[index].extensionName,
sizeof(result->extensionName),
"extension%03d",
index);
}
}
}
int main()
{
char *names[64];
uint32_t aCount = 0;
uint32_t count = 0;
vkEnumerateInstanceExtensionProperties(NULL, &count, NULL);
VkExtensionProperties *extension_names = malloc(sizeof(VkExtensionProperties) * count);
vkEnumerateInstanceExtensionProperties(NULL, &count, extension_names);
for (uint32_t i = 0; i < count; i++) {
names[aCount++] = strdup(extension_names[i].extensionName);
}
printf("First extension available: %s\n", names[0]);
free(extension_names);
printf("First extension available: %s\n", names[0]);
return 0;
}
Output
First extension available: extension000
First extension available: extension000
I don't have Vulcan installed, so I simulated the behavior of the function you called.
Helpful GCC Flags
While I have your attention, don't forget to compile your code with -Wall -Werror to help you fix problems at compile time:
$ gcc -Wall -Werror -o program program.c
You are assigning names[aCount++] = extension_names[i].extensionName;
i.e. you are copying the extension_names in the array of pointers that is names.
You can only free extension_names after you are done with using names
You freed the strings, so not sure what you expected to happen. The second printf() will access freed memory. If you want to keep the strings around longer, you should copy the string data, not just the pointers to that data. Also, you need to write safer code to avoid buffer overflows (you're not checking if you're writing past the end of names, for example.)
for (uint32_t i = 0; i < count && aCount < 64; i++, aCount++) {
// +1 for the '\0' terminator
const size_t len = strlen(extension_names[i].extensionName) + 1;
names[aCount] = malloc(len);
memcpy(names[aCount], extension_names[i].extensionName, len);
}
Note that you now also have to free() each element in names when you no longer need it.

strend function in C using pointers?

I have created a function for strend, which basically returns 1 if string t is present at the end of string s, however it never returns 1:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int strend(char *s, char *t) {
int p;
for (p = 0; p < strlen(s) - strlen(t); p++) {
*s++;
}
printf("%s\n%s\n", s, t);
if (s == t)
return 1;
return 0;
}
int main(void) {
int bool = strend("Hello", "ello");
printf("%i\n", bool);
return 0;
}
This gives me an output of:
ello
ello
0
So technically I should get 1. I assume the comparison using pointers is not used in this way?
You need to review your basic knowledge of C strings. There are lots of standard string functions in string.h that can help you with this test.
The basic problem is that the test s == t is valid, but you are comparing memory addresses here. You can see that is valid if you change the strings to test to
char test[] = "Hello";
int bool = strend_(test, test+1);
where test obviously is the same as your "Hello", and similarly, test+1 is the same as "ello" (try it by printing them). This correctly returns 1 with your routine.
In addition, I get two warnings:
on *s++; "warning: expression result unused [-Wunused-value]": you increment s but also ask what character is at that position through *s; and you don't use that information.
Fix by removing the * there.
on p < strlen(s) ..; "warning: comparison of integers of different signs: 'int' and 'unsigned long'", because strlen does not return a signed integer but an unsigned one (apparently, my header uses unsigned long).
Fix by declaring p as unsigned long, or even better, size_t.
Your entire routine can be condensed to a simple
int strend (char *s, char *t)
{
if (strlen(s) >= strlen(t) && !strcmp (s+strlen(s)-strlen(t),t))
return 1;
return 0;
}
It's not worth the trouble to cache the result of those four strlen calls into 2 temporary variables; a good compiler will work it out and do that for you. (A quick glance to the assembly output of the compiler I'm using – clang – shows it does, even with the default optimization settings.)
A slightly modified test, based on #M.M.'s comment:
int strend (char *s, char *t)
{
if (strlen(s) < strlen(t)) return 0;
return !strcmp (s+strlen(s)-strlen(t),t);
}
but attempting to optimize it this way is not as easy parsed as the routine above, and its assembly is ever so slightly "wordy" as well. Personally, I'd go for the more humanly readable version.
Use strcmp(3)
if (strcmp(s, t) == 0) return 1;
This actually compares the contents of the memory pointed to by s and t rather than their addresses.
Your code is broken in multiple ways:
The initial loop is a very cumbersome way to advance p by the difference of lengths if positive.
Once you have pointers at the same distance from the end of both strings, You should compare the characters with strcmp() (or memcmp() if you can first exclude the case of strlen(s) < strlen(t).
Comparing the pointers obtained after the loop will only work if t points inside the string pointed to by s, a special case that may or may not be produced by the compiler for the specific call in main: strend("Hello", "ello");.
Here is a modified version:
#include <string.h>
int strend(const char *str1, const char *str2) {
size_t len1 = strlen(str1);
size_t len2 = strlen(str2);
return len1 >= len2 && !memcmp(str1 + len1 - len2, str2, len2);
}
I corrected/modified your code, here is the code,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#pragma warning(disable:4996)
int strend(char *s, char *t)
{
int p,flag=0,count=0;//count will be the starting index for *t
p = strlen(s) - strlen(t);//this will be the starting index for *s
while(count<strlen(t))
{
if (*(s+p) == *(t+count))
{
flag = 1;
count++;
p++;
continue;
}
else
{
flag = 0;
break;
}
}
return flag;
}
int main(void)
{
int flag = strend("Hello", "ello");
printf("%i\n", flag);
return 0;
}
This code works too.
#include <stdio.h>
#include <string.h>
int strend (char *s1, char *s2);
void main ()
{
char str1[20] = "somethings";
char str2[20] = "things";
int f;
f = strend (str1,str2);
if (f==1)
printf ("1");
else
printf ("0");
}
int strend (char *str1, char *str2)
{
int l = strlen(str1) - strlen(str2);
str1 = str1 + l;
int d = strcmp(str1,str2);
if (d == 0)
return 1;
else
return 0;
}
this code works well.
int strend(char *s, char *t){
while(*t & *s){
if(*t == *s){
t++;
}
s++;
}
return *t==*s;
}

Debug error: Heap corruption detected

I am playing around a bit in C and trying to write a test program for kind of oop in c programming. I get the Error of the headline in Visual Studio 2010. In using gcc i don't get this error.
Can anyone point me to what i am doing wrong, besides using the wrong language for oop, and other off topic suggestions.
It seems like the error occurs when i free the top object in string_dispose, but i am not shure if that really says a lot about the location of the error.
Also any suggestions regarding code improvements are welcome. Using array syntax is not an option, because i want to try out pointer arithmetic.
The header file "strings.h":
#ifndef STRINGS_H
#define STRINGS_H
struct strings
{
char* s;
int len;
};
typedef struct strings string;
void string_init(string* s, char* chars, int len);
string* string_new(char* chars, int len);
void string_dispose(string* s);
#endif
The source file "strings.c":
#include "strings.h"
#include <stdlib.h>
void string_init(string* self, char* chars, int len)
{
int i;
self->s = (char*)malloc((len + 1) * sizeof(char*));
for (i = 0; i < len; i++)
{
*(self->s + i) = *(chars + i);
}
*(self->s + len) = '\0';
self->len = len;
}
string* string_new(char* chars, int len)
{
string* self;
self = (string*)malloc(sizeof(string*));
string_init(self, chars, len);
return self;
}
void string_dispose(string* self)
{
free(self->s);
free(self);
}
The main file:
#include <stdlib.h>
#include <stdio.h>
#include "strings.h"
int main(int argc, char* argv)
{
string* s;
int n = 5;
char* x = (char*)malloc((n + 1) * sizeof(char*));
x[0] = 'f';
x[1] = 'u';
x[2] = 'b';
x[3] = 'a';
x[4] = 'r';
x[5] = '\0';
s = string_new(x, n);
printf("the string: %s\n", s->s);
printf("the length: %d\n", s->len);
string_dispose(s);
printf("This is way more important");
return 0;
}
When you try to allocate memory for string, you only allocate enough memory for a pointer (string*):
self = (string*)malloc(sizeof(string*));
You should allocate sizeof(string) instead, since you want enough space to store the whole struct, not just a pointer to one. Since sizeof(string*) is smaller than sizeof(string), the other code writes outside of the allocated area, causing heap corruption.
Similarly, when mallocing memory for the characters, the size should be (len + 1) * sizeof(char).

Manipulating dynamic arrays in C

I am trying to solve StringMerge (PP0504B) problem from SPOJ (PL). Basically the problem is to write a function string_merge(char *a, char *b) that returns a pointer to an char array with string created from char arrays with subsequent chars chosen alternately (length of the array is the length of the shorter array provided as an argument).
The program I've created works well with test cases but it fails when I post it to SPOJ's judge. I'm posting my code here, as I believe it the problem is related to memory allocation (I'm still learning this part of C) - could you take a look at my code?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#define T_SIZE 1001
char* string_merge(char *a, char *b);
char* string_merge(char *a, char *b) {
int alen = strlen(a); int blen = strlen(b);
int len = (alen <= blen) ? alen : blen;
int i,j;
char *new_array = malloc (sizeof (char) * (len));
new_array[len] = '\0';
for(j=0,i=0;i<len;i++) {
new_array[j++] = a[i];
new_array[j++] = b[i];
}
return new_array;
}
int main() {
int n,c; scanf("%d", &n);
char word_a[T_SIZE];
char word_b[T_SIZE];
while(n--) {
scanf("%s %s", word_a, word_b);
char *x = string_merge(word_a, word_b);
printf("%s",x);
printf("\n");
memset(word_a, 0, T_SIZE);
memset(word_b, 0, T_SIZE);
memset(x,0,T_SIZE);
}
return 0;
}
Note: I'm compiling it with -std=c99 flag.
Off-by-one.
char *new_array = malloc (sizeof (char) * (len));
new_array[len] = '\0';
You're writing past the bounds of new_array. You must allocate space for len + 1 bytes:
char *new_array = malloc(len + 1);
Also, sizeof(char) is always 1, so spelling it out is superfluous, so are the parenthesis around len.
Woot, further errors!
So then you keep going and increment j twice within each iteration of the for loop. So essentially you end up writing (approximately) twice as many characters as you allocated space for.
Also, you're leaking memory by not free()ing the return value of string_merge() after use.
Furthermore, I don't see what the memsets are for, also I suggest you use fgets() and strtok_r() for getting the two words instead of scanf() (which doesn't do what you think it does).
char *new_array = malloc (sizeof (char) * (len*2 + 1));
new_array[len*2] = '\0';

String (array) capacity via pointer

I am tring to create a sub-routine that inserts a string into another string. I want to check that the host string is going to have enough capacity to hold all the characters and if not return an error integer. This requires using something like sizeof but that can be called using a pointer. My code is below and I would be very gateful for any help.
#include<stdio.h>
#include<conio.h>
//#include "string.h"
int string_into_string(char* host_string, char* guest_string, int insertion_point);
int main(void) {
char string_one[21] = "Hello mother"; //12 characters
char string_two[21] = "dearest "; //8 characters
int c;
c = string_into_string(string_one, string_two, 6);
printf("Sub-routine string_into_string returned %d and creates the string: %s\n", c, string_one);
getch();
return 0;
}
int string_into_string(char* host_string, char* guest_string, int insertion_point) {
int i, starting_length_of_host_string;
//check host_string is long enough
if(strlen(host_string) + strlen(guest_string) >= sizeof(host_string) + 1) {
//host_string is too short
sprintf(host_string, "String too short(%d)!", sizeof(host_string));
return -1;
}
starting_length_of_host_string = strlen(host_string);
for(i = starting_length_of_host_string; i >= insertion_point; i--) { //make room
host_string[i + strlen(guest_string)] = host_string[i];
}
//i++;
//host_string[i] = '\0';
for(i = 1; i <= strlen(guest_string); i++) { //insert
host_string[i + insertion_point - 1] = guest_string[i - 1];
}
i = strlen(guest_string) + starting_length_of_host_string;
host_string[i] = '\0';
return strlen(host_string);
}
C does not allow you to pass arrays as function arguments, so all arrays of type T[N] decay to pointers of type T*. You must pass the size information manually. However, you can use sizeof at the call site to determine the size of an array:
int string_into_string(char * dst, size_t dstlen, char const * src, size_t srclen, size_t offset, size_t len);
char string_one[21] = "Hello mother";
char string_two[21] = "dearest ";
string_into_string(string_one, sizeof string_one, // gives 21
string_two, strlen(string_two), // gives 8
6, strlen(string_two));
If you are creating dynamic arrays with malloc, you have to store the size information somewhere separately anyway, so this idiom will still fit.
(Beware that sizeof(T[N]) == N * sizeof(T), and I've used the fact that sizeof(char) == 1 to simplify the code.)
This code needs a whole lot more error handling but should do what you need without needing any obscure loops. To speed it up, you could also pass the size of the source string as parameter, so the function does not need to calculate it in runtime.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
signed int string_into_string (char* dest_buf,
int dest_size,
const char* source_str,
int insert_index)
{
int source_str_size;
char* dest_buf_backup;
if (insert_index >= dest_size) // sanity check of parameters
{
return -1;
}
// save data from the original buffer into temporary backup buffer
dest_buf_backup = malloc (dest_size - insert_index);
memcpy (dest_buf_backup,
&dest_buf[insert_index],
dest_size - insert_index);
source_str_size = strlen(source_str);
// copy new data into the destination buffer
strncpy (&dest_buf[insert_index],
source_str,
source_str_size);
// restore old data at the end
strcpy(&dest_buf[insert_index + source_str_size],
dest_buf_backup);
// delete temporary buffer
free(dest_buf_backup);
}
int main()
{
char string_one[21] = "Hello mother"; //12 characters
char string_two[21] = "dearest "; //8 characters
(void) string_into_string (string_one,
sizeof(string_one),
string_two,
6);
puts(string_one);
return 0;
}
I tried using a macro and changing string_into_string to include the requirement for a size argument, but I still strike out when I call the function from within another function. I tried using the following Macro:
#define STRING_INTO_STRING( a, b, c) (string_into_string2(a, sizeof(a), b, c))
The other function which causes failure is below. This fails because string has already become the pointer and therefore has size 4:
int string_replace(char* string, char* string_remove, char* string_add) {
int start_point;
int c;
start_point = string_find_and_remove(string, string_remove);
if(start_point < 0) {
printf("string not found: %s\n ABORTING!\n", string_remove);
while(1);
}
c = STRING_INTO_STRING(string, string_add, start_point);
return c;
}
Looks like this function will have to proceed at risk. looking at strcat it also proceeds at risk, in that it doesn't check that the string you are appending to is large enough to hold its intended contents (perhaps for the very same reason).
Thanks for everyone's help.

Resources