I want to create random data for testing. I want to fill an array with 100 strings of random length with the letter 'A'.
example:
array[0] = "AAAAA"
array[1] = "AAAAAAAA"
array[2] = "A"
...
char **create_string()
{
char **array = malloc(sizeof(**array));
srand((unsigned int)time(NULL));
int random = 0;
int i, j;
for(int i=0; i<100; i++)
{
random = rand() % 100;
for(j=0; j < random; j++)
{
array[i] = // some sort of string append that would be cheap.
}
}
}
I was looking at this C string append and they use strcat. Is there a better way to solve my problem? Since I will be running in a loop to create those random size strings.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char **create_string(size_t n) {
char **array = malloc(sizeof(char*) * n);
int i, j;
for(i=0; i<100; i++)
{
size_t sz = rand() % 100;
array[i] = malloc(sz + 1);
for(j=0; j < sz; j++) {
array[i][j] = 'A';
}
array[i][sz] = 0;
}
return array;
}
int main() {
char **array;
size_t i;
srand((unsigned int)time(NULL));
array = create_string(100);
for (i = 0; i < 100; i++)
printf("%s\n", array[i]);
return 0;
}
Alternatively, you can create a template string and copy required number of characters into each random string:
char **create_string(size_t n) {
char template[101];
char **array = malloc(sizeof(char*) * n);
int i;
for (i = 0; i < 100; i++)
template[i] = 'A';
template[100] = 0;
for(i = 0; i < n; i++) {
size_t sz = rand() % 100;
array[i] = malloc(sz + 1);
strncpy(array[i], template, sz);
array[i][sz] = 0;
}
return array;
}
This will depend on the distribution of string lengths that you want. This is a uniform distribution of string lengths, from 0 to 200.
int n = rand() % 200 * sizeof(*array);
array[i] = malloc(n + 1);
memset(array[i], 'A', n);
array[i][n] = '\0';
But you could have a Gaussian distribution, a Poisson distribution, etc.
char **create_string()
{
char **array = malloc(sizeof(char *) * 100);
srand((unisgned int)time(NULL));
int i;
for (i = 0; i <100;i++)
{
int random = rand() % 100;
array[i] = malloc(random);
memset(array[i],'A',random-1);
array[random-1] = '\0';
}
return array;
}
Problem for you to fix: what happens if random is 0? Also the random numbers will not be equaly distributed. Only modulo by a power of 2 will achieve that.
Here's an approach that doesn't put an upper bound on any individual string, but does put an exact bound on the total length of all strings. It also only calls malloc twice.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TOT_SIZE (5000) /* adjust to taste */
#define TOT_STRS (100)
char **create_strings()
{
char **array = (char**) malloc(TOT_STRS * sizeof(char *));
char *str = (char*) malloc(TOT_SIZE);
int zeros = 1;
int i;
memset(str, 'A', TOT_SIZE - 1);
str[TOT_SIZE - 1] = 0;
while (zeros < TOT_STRS)
{
int pos = rand() % TOT_SIZE;
if (str[pos] != 0)
{
str[pos] = 0;
zeros++;
}
}
array[0] = str;
for (i = 1; i < TOT_STRS; i++)
{
array[i] = array[i - 1] + strlen(array[i - 1]) + 1;
}
return array;
}
And a short test program:
int main()
{
char **a = create_strings();
int i;
for (i = 0; i < TOT_STRS; i++)
{
printf("%3d: %s\n", i, a[i]);
}
return 0;
}
This code assumes that all the random strings need to be non-overlapping. If they can overlap in memory, you only need one string, and an array of pointer to different starting points in that one string.
You do not have to allocate the real 100 strings. Firstly you just declare a long enough array char long_array[100]. and then you use random = rand() % 100; get the random. Secondly you just pass the long_array and the random to your function. Then your problem is solved.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
char **create_string(const size_t array_size,
const size_t string_size,
const unsigned char chr)
{
srand((unsigned)time(NULL));
char ** array = malloc(array_size * sizeof (char *));
size_t t;
for (t = 0; t < array_size; ++t) {
array[t] = malloc(string_size * sizeof(char));
array[t][string_size] = '\0';
memset(array[t], chr, (rand() % string_size) + 1);
}
return array;
}
main() {
char ** randstring = create_string(10, 7, 'A');
int t = 0;
for (; t < 10; ++t)
printf("%s\n", randstring[t]);
return 0;
}
Possible output
AAAAAA
AAAAA
AAAAAA
AAA
AAAAA
AAAAAA
AAAAAA
AAAAAAA
AAAA
AAAA
Related
I want to make a program that stores inputed words into a 2D array (it can be as many as you want) and once you input word 'END', program should get out of the while loop. But for now user can input max. 5 words, and once he do that, program should reallocate 2d array with more rows. But there's something wrong with reallocation and I dont know what.
Here's a code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 20
char** allocate(int n, int m) {
char** arr = (char**)malloc(sizeof(char*) * n);
for (int i = 0; i < n; i++)
arr[i] = (char*)malloc(sizeof(char) * m);
return arr;
}
void printList(char** polje, int n, int m) {
for (int i = 0; i < n; i++) {
printf("%s\n", polje[i]);
}
}
int main() {
int n = 5;
int index = 0;
char** list = allocate(5,MAX);
char input[MAX];
while (strcmp("END", input)) {
scanf(" %s", input);
if (index % 5 == 0) {
n += 5;
list = (char**)realloc(list, sizeof(char*) * n);
for (int i = 0; i < n; i++)
list[i] = (char*)realloc(list[i], sizeof(char) * MAX);
}
if (strcmp("END", input) != 0) {
strcpy(list[index], input);
index++;
}
}
printList(list, index, MAX);
return 0;
}
The problem is that realloc is being called with an invalid pointer.
After:
n += 5;
list = (char**)realloc(list, sizeof(char*) * n);
list[n - 5], list[n - 4], list[n - 3], list[n - 2], and list[n - 1] contain invalid pointer values. So in the subsequent:
for (int i = 0; i < n; i++)
list[i] = (char*)realloc(list[i], sizeof(char) * MAX);
The realloc is being passed invalid pointers when i is in the range n - 5 to n - 1.
We were asked to convert 2D static array to dynamic array. So I will need to create an array of pointers in which every pointer points to a different row. I have written this code but my code breaks when i=1 on line *(dynamicStr[i] + v) = rowStr[v]; Additionally, if I enable free(ptr); section my debugger gets stuck there for 6 or 7 times and then contiunes.
EDIT: In the end, I solved the problem with appying the answers #dodooft and #Viktor Terziev gave.
#include <stdio.h>
#include <stdlib.h>
void toDynamic(int x,int y, char toDyna[x][y]);
void toDynamic2(int x,int y, char toDyna[x][y]);
int main()
{
char toDyna[7][12] = {
"JOHN",
"MARK",
"PIERCEPIERCE",
"20",
"ROSIE",
"ALEX",
"MARLYN"
};
int x = 7;
int y = 12;
toDynamic2(x, y, toDyna);
return 0;
}
void toDynamic2(int x,int y, char toDyna[x][y]){
char *dynamicStr[x];
int rowToCheck = 0;
int size;
char *ptr;
int c;
for(int i = 0; i < x; i++){
printf("i: %d\n",i);
c = 0;
size = strlen(toDyna[rowToCheck]);
ptr = (char*) malloc(size * sizeof(char));
for(int j = 0; j < y; j++){
if(toDyna[i][j] != '\0'){
*(ptr+c) = toDyna[i][j];
c++;
} else{
break;
}
}
*(ptr+size) = '\0';
printf(" ");
char rowStr[size];
for(int v = 0; v < size; v++){
rowStr[v] = *(ptr+v);
printf("Added Char: %c\n", rowStr[v]);
*(dynamicStr[i] + v) = rowStr[v];
}
//free(ptr);
//printf("\n%s\n", rowStr);
//dynamicStr[i] = &rowStr;
rowToCheck++;
}
for(int i = 0; i < x; i++){
printf("%s\n", dynamicStr[i]);
}
}
EDIT: This is the working verion of the code:
#include <stdio.h>
#include <stdlib.h>
char** toDynamic(int x,int y, char toDyna[x][y]);
void free2DArray(int x, char **dynamicStr);
int main()
{
char toDyna[7][12] = {
"JOHN",
"MARK",
"PIERCEPIERCE",
"20",
"ROSIE",
"ALEX",
"MARLYN"
};
int x = 7;
int y = 12;
char **dynamicArr;
dynamicArr = toDynamic(x, y, toDyna);
free2DArray(x, dynamicArr);
return 0;
}
char** toDynamic(int x,int y, char toDyna[x][y]){
printf("Q2\n");
char **dynamicStr;
int rowToCheck = 0;
int size;
int c;
dynamicStr = (char*)malloc(x * sizeof(char*));
for(int i = 0; i < x; i++){
dynamicStr[i] = (char*)malloc(y * sizeof(char));
c = 0;
size = strlen(toDyna[rowToCheck]);
char *ptr = (char*) malloc((size + 1) * sizeof(char));
for(int j = 0; j < y; j++){
if(toDyna[i][j] != '\0'){
*(ptr+c) = toDyna[i][j];
c++;
} else{
break;
}
}
*(ptr+size) = '\0';
dynamicStr[i] = ptr;
rowToCheck++;
}
for(int i = 0; i < x; i++){
printf("%s\n", dynamicStr[i]);
}
printf("----------------------------\n");
return dynamicStr;
}
void free2DArray(int x, char **dynamicStr){
printf("Q3\n");
for(int i = 0; i < x; i++){
free(dynamicStr[i]);
printf("dynamicStr %d freed\n", i);
}
free(dynamicStr);
printf("dynamicStr array freed\n");
printf("----------------------------\n");
}
You define dynamicStr as an array of char pointers, when you are trying to assign a value to it with *(dynamicStr[i] + v) = rowStr[v]; you are basically copying the value of rowStr[v] to the address that is pointed by dynamicStr[i] + v. That address is not defined in your code, so you got a segfault.
If you are trying to fill dynamicStr with pointers to new arrays with dynamic memory, you should try something like
dynamicStr[i] = ptr;
where ptr is the pointer returned by the malloc call to the i-th row. Also, as you are working with strings you can use strcpy to copy the data from the static array to the dynamic one.
Its much easier than you think, please refer to strcpy documentation and strlen documentation, and (if you use my code) don't forget to free your memory.
char * * toDynamic2(size_t n, size_t m, char strings[n][m])
{
char * * arr = malloc(n * sizeof(char*));
for(size_t i = 0; i < n; ++i)
{
size_t size = strlen(strings[i]);
arr[i] = malloc((size + 1) * sizeof(char));
strcpy(arr[i], strings[i]);
}
for(size_t i = 0; i < n; ++i)
{
printf("%s\n", arr[i]);
}
return arr;
}
I have seen similar posts related to my question but I could not find any answer to understand the bug in this code.
So, I have a function whose return type can't be changed (for case 1). For case 2, I would like to know how to return char *a[];
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **myfunc(int n) {
char **a = malloc(n * sizeof(char *));
int i, j = 1;
for (i = 0; i < n; i++)
a[i] = malloc(9 * sizeof(char));
for (i = 0; i < n; i++) {
snprintf(a[i], 5, "%d", i);
return a;
}
int main() {
int num = 10, i;
char **ar = myfunc(num);
for (i = 0; i < num; i++)
printf("%s\n", ar[i]);
return 0;
}
1) In the myfunc(), how should I return a correctly? My compiler is throwing me a warning that return from incompatible pointer type.
2) In case, if I change my above myfunc() as follows, how should I return the modified buffer?
char ???myfunc(int n) {
char *a[n];
for (i = 0; i < n; i++)
a[i] = malloc(10 * sizeof(char));
return ?
}
3) In both cases, how should I handle the return inside the main() function?
Case 2:
char *myfunc(int n) {
static char *a[n];
int i;
for (i = 0; i < n; i++)
a[i] = malloc(9 * sizeof(char));
for (i = 0; i < n; i++)
snprintf(a[i], 5, "%d", i);
return a;
}
int main() {
int num = 10, i;
char *ar = myfunc(num);
for (i = 0; i < num; i++)
printf("%s\n", ar[i]);
return 0;
}
Your code was mis-indented, which makes it hard to read and hides silly mistakes such as the extra brace after the second for.
Once corrected for this mistake, the code compiles and runs fine:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **myfunc(int n) {
char **a = malloc(n * sizeof(char *));
int i;
for (i = 0; i < n; i++)
a[i] = malloc(9 * sizeof(char));
for (i = 0; i < n; i++)
snprintf(a[i], 9, "%d", i);
return a;
}
int main() {
int num = 10, i;
char **ar = myfunc(num);
for (i = 0; i < num; i++)
printf("%s\n", ar[i]);
return 0;
}
If you change myfunc() to define a as char *a[n];, you have a major problem when returning a from myfunc() as the array is defined only inside the scope of myfunc(). Returning its address, which is simply return a; will cause undefined behavior in main() because the space it points to might have been reused for other stuff, such as printf() local variables.
The third option where you define a as static char *a[n]; does not compile because the size of static objects must be known at compile time. Using local static objects is not advisable as it makes the program harder to understand and non-reentrant, with hidden internal state, etc. One such function is strtok() from <string.h>.
I am having trouble with assigning a return value of a function in heap part of the program. When I tried it in main, it gives an error "Segmentation fault". I believe it is because of the size of my array, which is the return value that I mentioned earlier because when I make my max_size smaller, the code works correctly (I think up to 45000). When I call the function in main, it uses the memory of stack, which is much smaller than memory of heap. Therefore I tried to call the function in heap and make the assignment in there but the compiler gave an error
deneme.c:6:15: error: initializer element is not constant
int *primes = listPrimes(1000000, &size);
After that I did some research and found out that stack is 8 MB memory, which is around 8000000 bytes. Then I estimated my array size as using the prime number theorem (up to 1000000, there are approximately 200000 primes) and sizeof(int) = 4 bit value so it gives 100000 bytes, which is much less than 8 MB. Therefore I have two questions in mind:
1. Why the compiler gives segmentation fault error although my array size is not too large?
2. How can I make the assigment in heap instead of main in order to avoid this problem?
Here is my code:
#include "mathlib.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
int *listPrimes(int max_size, int *size) {
*size = 1;
int *result = malloc(*size * sizeof(int));
int i;
int index = 1;
// Finding the list of primes using a sieve algorithm:
int *nums = malloc(max_size*sizeof(int));
for (i = 0; i < max_size; i++) {
nums[i] = i;
}
result[0] = 2;
int j = 2;
while (j < max_size) {
int k = j;
while (j*k <= max_size) {
nums[j*k] = 0;
k++;
}
if (j == 2) {
j++;
*size = *size + 1;
result = realloc(result, *size * sizeof(int));
result[index++] = nums[j];
}
else {
j += 2;
if (nums[j] != 0) {
*size = *size + 1;
result = realloc(result, *size * sizeof(int));
result[index++] = nums[j];
}
}
}
return result;
}
and main function:
#include <stdio.h>
#include <stdlib.h>
#include "mathlib.h"
int size = 0;
int *primes = listPrimes(1000000, &size);
int main() {
printf("size = %d\n", size);
for (int i = 0; i < size; i++) {
printf("%d th prime is %d\n", i+1, primes[i]);
}
free(primes);
return 0;
}
Use unsigned int for j, k and max_size in listPrimes and it works properly . Below is the tested code:
// #include "mathlib.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
int size = 0;
int *
listPrimes (unsigned int max_size, int *size)
{
*size = 1;
int *result = malloc (*size * sizeof (int));
int i;
int index = 1;
// Finding the list of primes using a sieve algorithm:
int *nums = malloc (max_size * sizeof (int));
for (i = 0; i < max_size; i++)
{
nums[i] = i;
}
result[0] = 2;
unsigned int j = 2;
while (j < max_size)
{
unsigned int k = j;
while (j * k <max_size)
{
nums[j * k] = 0;
k++;
}
if (j == 2)
{
j++;
*size = *size + 1;
result = realloc (result, *size * sizeof (int));
result[index++] = nums[j];
}
else
{
j += 2;
if (nums[j] != 0)
{
*size = *size + 1;
result = realloc (result, *size * sizeof (int));
result[index++] = nums[j];
}
}
}
free(nums);
return result;
}
int
main ()
{
int *primes = listPrimes (1000000, &size);
printf ("size = %d\n", size);
for (int i = 0; i < size; i++)
{
printf ("%d th prime is %d\n", i + 1, primes[i]);
}
free (primes);
return 0;
}
nums is allocated to have max_size elements, so the index of its last element is max-size-1.
This loop:
while (j*k <= max_size) {
nums[j*k] = 0;
k++;
}
may access an element with index j*k that equals max_size, thus writing beyond the end of the array. The loop should be limited to j*k < max_size.
Regarding your second question, the size of the result array is determined while finding the primes and is not readily calculable in advance, so it cannot easily be allocated prior to calling listPrimes. It could be done by evaluating the prime-counting function, but that is likely more than you want to do for this project.
I'm using a for loop to create an 100 element array of char. I on the first run, I want to change all of its values to 1, the second run, I want its every second values to 0
char array[ 100 ] = { 0 };
int toggle_swith(char a[]) {
for (i = 0; i < 100; i++) {
printf(array[i] + "1 ");
}
}
int main( void ) {
int i;
for (i = 0; i < 100; i++) {
printf(array[i] + "0 ");
toggle_switch();
}
}
You need a function which initializes the array:
void InitializeArray(char Array[], int Length) {
int i;
for (i = 0; i < Length; i++) {
Array[i] = '1';
}
}
You need a function which changes every 2nd element:
void ChangeEverySecondElement(char Array[], int Length) {
int i;
for (i = 1; i < Length; i += 2) {
Array[i] = '0';
}
}
You need a function to print the array :
void PrintArray(char Array[], int Length) {
int i;
for (i = 0; i < Length; i++) {
putchar(Array[i]);
putchar(' ');
}
putchar('\n');
}
Then you need to put them together
int main() {
char Array[100];
InitializeArray(Array, 100);
PrintArray(Array, 100);
ChangeEverySecondElement(Array, 100);
PrintArray(Array, 100);
return 0;
}
If you are trying to learn C, I recommend the book I learned it from, C by Example written by Greg Perry.
you can do it all at once
for (i=0; i<100; i++) array[i]=(i%2)+'0';
a typical attempt at optimization could look like:
#define BUFSZ 100
int main(){
char buf[BUFSZ];
int *bp=(int *)&buf, i=(BUFSZ/sizeof(int));
/* handle aligned words 4 bytes at a time */
while (i) bp[--i]='0101'; /* for 64 bit use '0101'|('0101' <<32) */
/* handle unaligned bytes */
for(i=(BUFSZ/sizeof(int))*sizeof(int);i<BUFSZ;i++)buf[i]=1-i%2+'0';
write(1,buf,BUFSZ);
}
Initially you want to make all your array elements as 1
You can use memset
memset(array,1,100)
This will clear all elements. But if you insist on using a loop then,
#define ARRAY_SIZE 100
char array[ARRAY_SIZE] = {0};
for(int count = 0; count < ARRAY_SIZE; count++)
{
array[count] = 1;
//If you want to print it, use:
printf("%d",array[count]; // You can also use %c
}
To make alternate element 0,
for(int count = 0; count < ARRAY_SIZE; (count = count + 2)) //Count + 2 will hop every alternate element
{
array[count] = 0;
}
Again, You can add printf() if you want.
Print statement should look something like this.
printf("%c0",array[i]);
I suggest you look up Beginner C tutorial for more info.