copy two arrays of int to one char* in C - c

I have to arrays of int for example arr1={0,1,1,0,0}, arr2={1,0,1,1,1} and I need to return 1 char* created by malloc that will be shown like this : "01100,10111".
when I do for loop it doesn't work, how can I do it ?
char* ans = (char*)malloc((size * 2+1) * sizeof(int));
for (int i = 0; i < size; i++)
ans[i] = first[i];
ans[size] = ",";
for (int i = size+1; i < 2*size+1; i++)
ans[i] = second[i];

Among the multitude of problems:
Your allocation size is wrong. It should include space for the separating comma and the terminating nullchar. sizeof(int) is wrong regardless, it should be sizeof(char) and as-such can be omitted (sizeof(char) is always 1).
Your storage is wrong. You want to store characters, and your values should be adjusted relative to '0'.
Your indexing of the second loop is wrong.
In reality, you don't need the second loop in the first place:
char* ans = malloc(size * 2 + 2);
for (int i = 0; i < size; i++)
{
ans[i] = '0' + first[i];
ans[size+1+i] = '0' + second[i];
}
ans[size] = ',';
ans[2*size+1] = 0;
That's it.

1.
char* ans = (char*)malloc((size * 2+1) * sizeof(int));
What is size here? It is not defined and declared in the provided code.
You do not need to cast the return value of malloc() to char. In fact, you do not need to cast the return value of malloc() anymore. It is a habit from the early C days.
Why do you need a char pointer here at all exactly? If you want to print 01100,10111 there is no need to use a char pointer for the output of the integer values.
2.
for (int i = 0; i < size; i++)
ans[i] = first[i];
Again what is size here?
What is first here? If it isn´t a pointer this statement is invalid.
3.
ans[size] = ",";
This operation is invalid. You are trying to assign a string to a pointer.
By the way, I don´t know what you trying to do with this statement. You can incorporate the comma separate in the output of 01100,10111, without your intend to include it int the memory of the int arrays itself.
4.
for (int i = size+1; i < 2*size+1; i++)
ans[i] = second[i];
Same as above: What is value and the type of size?
What is second? If it isn´t it a pointer this statement is invalid.
5.
To answer to the question title:
(How to) Copy two arrays of int to one char* in C
This isn´t possible. You can´t copy two arrays with its data to a pointer to char.

There are at least four issues with your code.
You malloc the wrong size, you want to use sizeof(char).
You need to zero terminate it, so you need to add extra room for the terminating zero
char* ans = (char*)malloc((size * 2+2) * sizeof(char));
second[size * 2+1] = 0;
Also the indexing of the second loop is wrong. You are accessing second array out of bounds. Make the loop more like the first.
We also need to convert the integer value to a char in the loops.
for (int i = 0; i < size; i++)
ans[size+i+1] = second[i] + '0';

Related

Replace a subarray with a character in C

I have an array and I need to replace a subarray from this array with a character.
unsigned char * data = {'a','b','c','d','e'};
I need to delete 'a','b''c' and insert 'R'
The final array will be: unsigned char * data = {'R','d','e'};
With only 3 elements.
How can I do that in C?
You say you think of data as an array, therefore it is better that you declare data as an array instead of a pointer. (The way your code is now you have a pointer that is initialized incorrectly by casting the character 'a' to a char * pointer. That way it will not be pointing anywhere.)
You can replace characters by assigning to elements of the array, and you can shift parts of the data in the array using memmove.
Which means that maybe you want something like this:
unsigned char data[] = {'a','b','c','d','e'};
data[0] = 'R';
memmove(data + 1, data + 3, sizeof(data) - 3);
The memmove call moves sizeof(data) - 3 bytes of data from address data + 3 to address data + 1. The function memmove even works when the regions of memory between which you are moving bytes of data overlap.
If you then print the relevant part of your data:
fwrite(data, 1, sizeof(data) - 2, stdout);
putchar('\n');
This will get you the output:
Rde
However, notice that the size of the array will not have changed. It still will be five characters long. So replacing abc by something longer than three characters will not work like this. Also, this array is not a null-terminated string, which is the more usual way to have sequences of characters in C.
If you prefer to use a string "abcde" instead of what you are doing now (but then why call it "data"?), add a comment below this answer, and I'll extend it.
for(int i = 0; i < 5; i++){
if (data[i] > 96 && data[i] < 100) data[i] = 'R';
}
How about the following way?
unsigned char * data = {'a','b','c','d','e'};
int length = strlen(data);
unsigned char * output = (unsigned char *)malloc(sizeof(unsigned char)*length);
for(int i = 0, j =0; i < length; i++, j++){
if (i+2 < length && data[i] == 'a' && data[i+1] == 'b && data[i+2] == 'c') {
output[j]='R';
i++;
i++;
}
else
output[j]=data[i];
}

Dynamically allocating a 2D array in C

I've been reading around and I've been applying what I've been reading to my code but I am not sure if I am missing something.. the 2d array is suppose to mirror sudoku.
I know the problem area is in my arrayMake function.
My professor recommended using a cast with the malloc call so:
sudoku = (int**)malloc(sudokus*sizeof(int*)); but that did not work for me.
int main(){
int sudokus;
int** sudoku;
sudokus = getUserInfo();
sudoku = arrayMake(sudokus);
/*for (int i = 0; i < (SIZE*sudokus), i++;){
for (int j = 0; j < SIZE, j++;){
printf("Numbers[%d][%d]:%d", i, j, sudoku[i][j]);
}
}*/
system("pause");
return 0;
}
int getUserInfo(){
int sudokus;
printf("How many Sudokus are you checking today?\n");
scanf("%d{^\n]\n", &sudokus);
return sudokus;
}
int** arrayMake(int sudokus){
int **sudoku;
int realsize;
realsize = 9 * sudokus;
sudoku = malloc(realsize*sizeof(int*));
if (sudoku == NULL){
printf("Memory allocation failed");
return 0;
}
for (int i = 0; i < realsize, i++;){
sudoku[i] = malloc(9 * sizeof(int));
if (sudoku[i] == NULL){
printf("Memory allocaiton failed");
return 0;
}
}
return sudoku;
}
My professor recommended using a cast with the malloc call so: sudoku = (int**)malloc(sudokus * sizeof(int*)); but that did not work for me.
To dynamically allocate for 2D array, you usually need to do two steps. Your code is not clear as you include a realsize = 9 * sudokus which doesn't make sense. Anyway, for simplicity, lets assume your sudoku is a 3x3 matrix. You'll need to:
Allocate for the pointer to pointer to int:
int **sudoku = malloc( 3 * sizeof( int * ) );
Allocate for each of the individual pointer to int:
for( int i = 0; i < 3; i++ )
sudoku[i] = malloc( 3 * sizeof( int ) );
From what I see your problem exists in your for loops where you have:
for (i = 0;i < realsize , i++)
when you really meant:
for (i = 0;i < realsize ; i++)
^
Note the change of , to ;
scanf("%d{^\n]\n", &sudokus); is a mistake.
I guess you meant the { to actually be a [ but the format string is still wrong even after that change. I think you intended to consume the rest of the input, up to and including a newline character. However, your format string does not actually do that.
Scanf'ing for \n actually means consume any amount of whitespace, so in fact this code (with the [ fix) would continue waiting for input until there was a newline, and also another non-whitespace character typed after the newline.
Better would be:
scanf("%d", &sudokus);
int ch;
while ( (ch = getchar()) != '\n' && ch != EOF ) { }
There are a few different ways to achieve the same goal. (Note that scanning for %d[^\n]%c is not one of them; that string is also broken).
Also I would suggest a different variable name than sudokus. It's confusing having two similarly-named variables sudoku and sudokus. Name it something that reflects its meaning.
For allocating your array, it would be much simpler to take out the arrayMake function and write something like:
int sudoku[9][9];
(I couldn't figure out what sudokus was supposed to mean or what realsize was going to be, but you could put your intended dimension inside the square brackets there).

Malloc affecting random integer value

I'm writing a virtual memory simulator in C, compiling on linux, and I'm getting something rather strange. It takes in a file IO, which I put into an int* plist.
I've printed this "plist" array, and it comes out to
0 100
1 200
2 400
3 300
etc
The problem is that it seems malloc or something is randomly changing plist[3] to 0. It doesn't seem like it should be that way, but I've put a print statement at every line of code to print plist[3], and
tables[i].valid = (char*) xmalloc(num_pages * sizeof(char));
is where it changes. plist[3] = 300 before the line, 0 after it. And it only does this when i = 2. The first 3 rounds of the loop run fine, and on round 3, it changes the values for round 4. I have no idea why, it makes little sense that malloc would change a value in an array that's completely unrelated - is it possible I've gone over some space limit, even though I'm using the heap for basically everything? Would it just change values in random arrays if I did?
for(i = 0; i < 4; i++){
num_pages = plist[i] / P1;
tables[i].page_num = (char**) xmalloc(num_pages * sizeof(char*));
tables[i].valid = (char*) xmalloc(num_pages * sizeof(char));
//initialize page numbers and valid bits
for(j = 0; j < 10; j++){
tables[i].page_num[j] = (char*) xmalloc(16*sizeof(char));
tmp = itoa(i, tmp);
strcat(tables[i].page_num[j], tmp);
strcat(tables[i].page_num[j], "p");
tmp = itoa(j, tmp);
strcat(tables[i].page_num[j], tmp);
tables[i].valid[j] = 0;
}
}
Here's the struct for tables:
typedef struct s_page_table
{
char** page_num;
char* valid;
} t_page_table;
And this is xmalloc (it's just a wrapper to make it easier):
void* xmalloc(int s)
{
void* p;
p = malloc(s);
if (p == NULL)
{
printf("Virtual Memory Exhausted");
exit(1);
}
return p;
}
EDIT: If I take out both lines referencing tables[i].valid, the problem does not exist. plist[3] stays the same. num_pages is always >= 10. I set j to be 0 to 10 just to have less output for debugging purposes.
EDIT 2: If I change valid from a char* to an int* it doesn't work. If I change it to an int, it does.
There are several possibilities, including (but not limited to):
tables[i] is out of bounds;
plist contains a dangling pointer (i.e. it's been deallocated);
plist hasn't been initialised;
plist isn't as large as you think, i.e. plist[3] is out of bounds.
If you can't figure out the problem by looking at the code, valgrind is your friend.
OK. So I believe the problem turned out to be playing with the strings before initializing everything. I'm not entirely certain the reason, maybe someone else can elaborate, but when I encapsulated JUST the initialization in its own function, like only doing mallocs, and then separately created the strings afterwards, the plist variable was unaffected.
For those interested, the encapsulated function looked like this:
t_page_table* table_builder(int* p, int x, int num_tables)
{
t_page_table* ret = xmalloc(num_tables * sizeof(*ret));
int i, tmp, j;
for(i = 0; i < num_tables; i++){
tmp = (p[i]/x);
ret[i].page_num = xmalloc(tmp * sizeof(char*));
ret[i].valid = xmalloc(tmp * sizeof(char));
for(j = 0; j < tmp; j++){
ret[i].page_num[j] = xmalloc(16 * sizeof(char));
ret[i].valid = 0;
}
}
return ret;
}

string array where the number of rows is input by user in C

char words[wordCount][MAX_WORD_LENGTH];
I know i need to use malloc to be able to have a user defined length of an array but how would i do this with a 2d array?
char words[MAX_WORD_LENGTH];
words = (words *) malloc (wordCount)
Would something like that work?
Just started using c so im still getting used to it.
You have to do this first:
char *words = calloc(wordCount * MAX_WORD_LENGTH, sizeof(char));
and access words[i][j] as words[i*MAX_WORD_LENGTH + j]
This link may help
Pointers can be easily used to create a 2D array in C using malloc. The idea is to first create a one dimensional array of pointers, and then, for each array entry, create another one dimensional array.
Another answer is present in the stack overflow it self
malloc() for a 2D array (using pointer-to-pointer)
If you want to index the array using two subscripts words[i][j], then you need to do two allocations (well, you could make it one if you're really confident in your handling of pointers, but you'd do better with two if you're asking this question).
You need to allocate enough space for the pointers, and enough space for the data:
char **words = malloc(wordCount * sizeof(*words));
char *data = malloc(wordCount * MAX_WORD_LENGTH);
if (words == 0 || data == 0)
{
free(data);
free(words);
...report error?...
}
for (int i = 0; i < wordCount; i++)
words[i] = data + (i * MAX_WORD_LENGTH);
...now you can use words[i][j] to access the jth character of the ith word...
If you want to have user defined size for each word pointer in the words array :
char * words[wordCount];
for (i =0; i< wordCount; i++)
words[i] = malloc(sizeof(char)*User_defined_Size);
char **words = NULL;
words = (char **)malloc(sizeof(char*) * user_defined_size_A);
for(i = 0; i < user_defined_size_A; i++) {
words[i] = (char*) malloc(sizeof(char) * user_defined_size_B);
}
you can try this...

Concat LPSTR in C

Trying to use as basic C as I can to build a list of numbers from 1-52 in a random order (deck of cards). Everything works, but all of my attempts to concat the strings and get a result end in failure. Any suggestions? NOTE: This is not homework it's something I'm using to create a game.
// Locals
char result[200] = ""; // Result
int card[52]; // Array of cards
srand(time(0)); // Initialize seed "randomly"
// Build
for (int i=0; i<52; i++) {
card[i] = i; // fill the array in order
}
// Shuffle cards
for (int i=0; i<(52-1); i++) {
int r = i + (rand() % (52-i));
int temp = card[i]; card[i] = card[r]; card[r] = temp;
}
// Build result
for (int c=0; c<52; c++) {
// Build
sprintf(result, "%s%d", result, card[c]);
// Comma?
if ( c < 51 )
{
sprintf(result, "%s%s", result, ",");
}
}
My end result is always garbled text. Thanks for the help.
You keep writing to the same position of "result".
sprintf is not going to do the appending for you.
You may consider, after each sprintf, get the return value (which is the number of char written), and increment the pointer to result buffer. i.e. something like:
(psuedo code):
char result[200];
char * outputPtr = result;
for (int c=0; c<52; c++) {
// Build
int n = sprintf(outputPtr, "%d%s", card[c], (c<51 ? "," : ""));
outputPtr += n;
}
Are we writing C++ or C? In C++, concat-ing a string is just:
string_out = string_a + string_b
…since you'd be using std::string.
Furthermore, if this is C++, the STL has a std::shuffle function.
If this is C, note that all your sprintfs aren't concatenating strings, they're just overwriting the old value.
I think, if memory serves, that sprintf will always write into the buffer starting at byte 0. This means that you would be writing the first couple of bytes over and over again with a number, then a comma, then a number. Check if your first bytes are ",[0-9]" - if so, that's your issue.
This would add a comma between each number in the result string:
// Get a pointer to the result string
char* ptr = &result[0];
for (int c = 0; c < 52; c++) {
// Add each cards number and increment the pointer to next position
ptr += sprintf(ptr, "%d", card[c]);
// Add a separator between each number
if (c < 51) {
*ptr++ = ',';
}
}
// Make sure the result string is null-terminated
*ptr = 0;

Resources