Pointers aren't being transferred to allocated memory - c

I have a school assignment, and everything works just fine except for one part, which I cannot figure out. The following is the snippet of code where my issue is occurring:
//something goes wrong here, wont copy over
puts("bravo");
//add to end of the list
int size_list = sizeof(environ);
//char** tmp_ptr = ( char** )calloc( size_list + 1, ( size_list + 1 ) * sizeof( char* ) );
char** tmp_ptr = ( char** ) malloc ( ( size_list + 1 ) * sizeof( char* ) );
int k;
for ( k = 0; k < size_list; ++k )
{
tmp_ptr[k] = environ[k];
//memcpy(tmp_ptr[k],environ[k],sizeof(environ[k]));
}
//char** tmp_ptr= (char**)realloc(*environ, size_list+2);
environ = tmp_ptr;
environ[size_list] = (char*)malloc(len_string+1);
strcpy(environ[size_list],full_string);
return 1;
You can ignore the "bravo", it was for me to locate where the problem was occurring. I am trying to get environ to have the new list of variables, but when I set it equal to tmp_ptr, it is empty. I'm pretty sure that the values are getting copied over, but I do not know what is wrong.
Does the data in tmp_ptr get deleted when the function ends? Is that a possible explanation? How can I properly allocate and copy over the memory. I tried using realloc, but that gave me invalid pointer errors, so I am relying on calloc or malloc. Thanks in advance.

environ's length isn't sizeof(environ), since environ is a char ** (and thus sizeof(environ) is 4 or 8 depending on your platform). What you're doing is effectively wiping out most of environ because you only copy the first few entries.
To find out how many entries are in environ, do
int cnt = 0;
char **envp = environ;
while(*envp++) cnt++;
I should also note a problem with the approach: since environ is a NULL-terminated string array (not to be confused with 'null-terminated string'), you have to replace the NULL at the end with your own entry, then add a new NULL after your new entry. Currently, your code (if it calculated the size correctly) would have added your entry after the NULL, and would have not been visible to the program.
Side note: messing with environ this way is definitely not recommended. Use getenv/setenv instead; if you need to mass-set the environment, try using execve instead. (So, in your case, you can simply setenv("varname", "varvalue", 1) to add varname=varvalue to the environment (and replace an existing mapping to varname if it is already set).

environ is a pointer, meaning that sizeof(environ) is not the number of items in that array. Rather, it's the size of the pointer, probably four or eight in your case.
If environ is the same sort of structure as argv (an array of character pointers where the last one is a null pointer), you will need to determine its size by walking through the array until you find NULL.
Something like (untested, but the idea is sound):
char **envPtr = environ;
int size_list = 0; // probably should be size_t
while (*envPtr != NULL) {
envPtr++;
size_list++;
}
You can see the effect in this complete program (with a few changes to get around some other bugs):
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define full_string "xyzzy=plugh"
#define len_string strlen(full_string)
int main (int argc, char **argv) {
int k, size_list = sizeof(environ);
char **tmp_ptr = malloc ((size_list + 1) * sizeof ( char*));
for (k = 0; k < size_list; ++k) printf ("[%s]\n", environ[k]);
for (k = 0; k < size_list; ++k) tmp_ptr[k] = environ[k];
tmp_ptr[size_list] = NULL;
environ = tmp_ptr;
environ[size_list] = malloc (len_string + 1);
strcpy(environ[size_list],full_string);
printf ("=====\n");
for (k = 0; k <= size_list; ++k) printf ("[%s]\n", environ[k]);
return 0;
}
This outputs only four of my environment variables because I have four-byte pointers:
[ORBIT_SOCKETDIR=/tmp/orbit-pax]
[SSH_AGENT_PID=1978]
[GPG_AGENT_INFO=/tmp/seahorse-tNDhG9/S.gpg-agent:2005:1]
[TERM=xterm]
=====
[ORBIT_SOCKETDIR=/tmp/orbit-pax]
[SSH_AGENT_PID=1978]
[GPG_AGENT_INFO=/tmp/seahorse-tNDhG9/S.gpg-agent:2005:1]
[TERM=xterm]
[xyzzy=plugh]
Changing the code to correctly determine the size of the environment:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define full_string "xyzzy=plugh"
#define len_string strlen(full_string)
int main(int argc, char **argv) {
int k, size_list = 0;
char **envPtr = environ;
while (*envPtr != NULL) {
envPtr++;
size_list++;
}
char **tmp_ptr = malloc ((size_list + 1) * sizeof (char*));
for (k = 0; k < size_list; ++k) printf ("[%s]\n", environ[k]);
for (k = 0; k < size_list; ++k) tmp_ptr[k] = environ[k];
tmp_ptr[size_list] = NULL;
environ = tmp_ptr;
environ[size_list] = malloc (len_string + 1);
strcpy(environ[size_list],full_string);
printf ("=====\n");
for (k = 0; k <= size_list; ++k) printf ("[%s]\n", environ[k]);
return 0;
}
gives me the lot:
[ORBIT_SOCKETDIR=/tmp/orbit-pax]
[SSH_AGENT_PID=1978]
[GPG_AGENT_INFO=/tmp/seahorse-tNDhG9/S.gpg-agent:2005:1]
[TERM=xterm]
[SHELL=/bin/bash]
[GTK_RC_FILES=/etc/gtk/gtkrc:/home/pax/.gtkrc-1.2-gnome2]
[WINDOWID=62914564]
[GNOME_KEYRING_CONTROL=/tmp/keyring-RADe9n]
[GTK_MODULES=canberra-gtk-module]
[USER=pax]
:
[XAUTHORITY=/var/run/gdm3/auth-for-pax-AO1dYc/database]
[_=./testprog]
=====
[ORBIT_SOCKETDIR=/tmp/orbit-pax]
[SSH_AGENT_PID=1978]
[GPG_AGENT_INFO=/tmp/seahorse-tNDhG9/S.gpg-agent:2005:1]
[TERM=xterm]
[SHELL=/bin/bash]
[GTK_RC_FILES=/etc/gtk/gtkrc:/home/pax/.gtkrc-1.2-gnome2]
[WINDOWID=62914564]
[GNOME_KEYRING_CONTROL=/tmp/keyring-RADe9n]
[GTK_MODULES=canberra-gtk-module]
[USER=pax]
:
[XAUTHORITY=/var/run/gdm3/auth-for-pax-AO1dYc/database]
[_=./testprog]
[xyzzy=plugh]
For what it's worth, your code had the following problems:
The incorrect calculation of the environment size, obviously.
Casting the return value from malloc - this is ill-advised in C since it can cause code problems to be hidden from you.
Not setting the final element of the new list to NULL.
Not checking for out-of-memory conditions.
All these except the last are fixed in my final code sample above.

Related

Initialize the arrays inside an array of char* using a loop

I need to create an array of strings, each representing a card of the Spanish deck:
#define __USE_MINGW_ANSI_STDIO 1
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
char *type[4]= {"copas", "basto", "espada", "oro"};
char *number[10]= {"Uno", "Dos", "Tres", "Cuatro", "Cinco", "Seis", "Siete", "Diez", "Once", "Doce"};
char *deck[40];
int deckIndex= 0;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 10; j++) {
char card[100] = "";
strcat(card, number[j]);
strcat(card, " de ");
strcat(card, type[i]);
strcat(card, "\n");
deck[deckIndex]= card;
deckIndex++;
}
}
for (int i = 0; i < 40; i++)
{
printf("%s\n", deck[i]);
}
return 0;
}
However, all entries of deck[] point to the same string. As a result, "Doce de oro" is printed 40 times. I don't understand why this happens, but I've theorized it's because card[] is being reinitialized in the same memory direction, and overrides what was already written there in the previous iteration. If I'm right, I would have to declare every array separately, but I have no idea how to do that without writing 40 different arrays.
Tldr:
¿Why do all entries of deck[] point to the same location?
¿How do I fix it?
(Btw suggestions for a better title are appreciated)
In C, memory on the stack is allocated in terms of Scopes. So yes, your theory is right. You are rewriting on the same location.
To fix your program, there are two possible solutions I can think of.
You can use Multidimensional Arrays.
Or you can allocate memory in heap using malloc (but make sure to free it once you are done with it)
As pointed out in the comments, in the deck[deckIndex]= card; line, you are assigning the same pointer1 to each of your deck elements – and, worse, a pointer to a variable (the card array) that is no longer valid when the initial nested for loop goes out of scope.
To fix this, you can make copies of the card string, using the strdup function, and assign the addresses of those copies to the deck elements. Further, as also mentioned in the comments, you can simplify the construction of the card string using a single call to sprintf, rather than using multiple strcat calls.
Here's how you might do that:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
char* type[4] = { "copas", "basto", "espada", "oro" };
char* number[10] = { "Uno", "Dos", "Tres", "Cuatro", "Cinco", "Seis", "Siete", "Diez", "Once", "Doce" };
char* deck[40];
int deckIndex = 0;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 10; j++) {
char card[100] = "";
sprintf(card, "%s de %s", number[j], type[i]);
deck[deckIndex] = strdup(card);
deckIndex++;
}
}
for (int i = 0; i < 40; i++) {
printf("%s\n", deck[i]);
}
// When you're done, be sure to free the allocated memory:
for (int i = 0; i < 40; i++) {
free(deck[i]);
}
return 0;
}
If your compiler does not support the strdup function (most do, and it is part of the ISO C Standard from C23), writing your own is very simple:
char* strdup(const char *src)
{
char* result = malloc(strlen(src) + 1); // Add one to make room for the nul terminator
if (result) strcpy(result, src);
return result;
}
1 Well, formally, a new card array is born on each iteration of the inner for loop, but it would be a very inefficient compiler that chose to do that, rather than simply re-using the same memory – which is clearly what is happening in your case.

Dynamic reallocation of a square matrix

i'm tryng to create a function which adds dynamically 1 row and 1 column to a square matrix everytime i need. I'm posting the code as an example, there i start with a "1x1 matrix" of integers and i try to add a row and a column 5 times to obtain a fianl 5x5 matrix, i don't understand why the OS stops immediately the execution. In the for cycle first i reallocate the "column" array of pointers adding a new one (so a new row) then for each block of it (so for each row) i reallocate others N blocks of memory. It seems that i try to access to a forbidden address of memory but i don't understand why, what's wrong?
P.S: my ennglis could not be perfect so if you don't understand what i'm trying to say i will explaind better.
#include <stdlib.h>
#include <malloc.h>
#include <stdbool.h>
#include <stdio.h>
int **M,N;
int main(int argc, char** argv) {
N = 1;
M = (int**)malloc(sizeof(int*));
M[0] = (int*)malloc(sizeof(int));
for (int i = 0; i < 5; i++) {
N++;
M = (int**)realloc(M, N * sizeof(int*));
for (int k=0; k<N; k++)
M[k] = (int*)realloc(M[k], N * sizeof(int));
}
}
Before entering the loop, you have M pointing to a single int * and M[0] pointing to a single int.
On the first iteration of the loop, you use realloc to modify M to point to an array of 2 int *. The first one still points to a single int, but the second one is uninitialized. When you then try to call realloc on M[1], it reads an uninitialized pointer invoking undefined behavior. In this case it manifests in a crash.
You need to initialize the newly added element of M to NULL so that realloc will work properly.
M = realloc(M, N * sizeof(int*));
M[N-1] = NULL;
for (int k=0; k<N; k++) {
M[k] = realloc(M[k], N * sizeof(int));
}
Also, don't cast the return value of malloc/realloc
When you use realloc to expand an array, the new expanded elements in the array are not initialized. So when you realloc M, the additional pointers to memory are undefined, not NULL, so you cannot reference the expanded elements of M[] in the second realloc, until you initialize them to NULL.
#include <stdlib.h>
#include <malloc.h>
#include <stdbool.h>
#include <stdio.h>
int **M,N;
int main(int argc, char** argv) {
N = 1;
M = (int**)malloc(sizeof(int*));
M[0] = (int*)malloc(sizeof(int));
for (int i = 0; i < 5; i++) {
N++;
M = (int**)realloc(M, N * sizeof(int*));
// Ensure the last M[] is NULL
M[N-1] = NULL;
for (int k=0; k<N; k++)
M[k] = (int*)realloc(M[k], N * sizeof(int));
}
}

Strange behavior while filling dinamically allocated 2D char array in C

I need to create a program that plays the game Hex on a 14x14 board.
So I created, allocated and filled the board with '-' (our pattern for empty spaces).
When I try to print the board's coordinates, I don't always get '-' but some random characters.
Also, if I try to printf array[i][j] on the createBoard function after the line "board[i][j] = '-';" I get a segmentation fault right after it prints tab[8][0].
What is causing this and how can I fix it?
My code:
#include <stdio.h>
#include <stdlib.h>
char **createBoard()
{
/*Allocates a 14x14 matrix and fills it
*with '-' to create the board.*/
int i, j;
char **board;
board = malloc(14);
if (!board) exit(1);
for (i = 0; i < 14; i++){
board[i] = malloc(14);
if (!board[i]) exit (1);
for (j = 0; j < 14; j++)
board[i][j] = '-';
}
return board;
}
int main()
{
int i, j;
char **board = createBoard();
for (i = 0; i < 14; i++)
for (j = 0; j < 14; j++)
printf("tab[%d][%d]: %c\n",i, j, board[i][j]);
return 0;
}
For starters it is not clear why you don't want to declare an array instead of allocating dynamically numerous one-dimensional arrays.
As for the code then this memory allocation
board = malloc(14);
is invalid. You have to write
board = malloc( 14 * sizeof( char * ));
Also you should free all the allocated memory in the reverse order relative to its allocation before the program ends.
Take into account that it is always better to use named constants instead of magic numbers. At least you could write either
#define N 14
before main
or
const int N = 14.
and use the variable N everywhere where you are using magic number 14.
By the way according to the C Standard function main without parameters shall be declared like
int main( void )
The variable *board is a pointer, but you only allocate one byte for each array element, which should be
#define DIM 14
board = malloc(DIM * sizeof *board);
Following that up with the second allocation
board[i] = malloc(DIM * sizeof **board);
This also allows (a) that the dimension 14 is hard coded in only one place in the program and (b) the allocation will survive if you later make the board's element a different type, for example a struct, as the program develops.

Get C XOR return value

In the for loop, it prints the correct value 11100001 in each loop, but the main call print char_str is blank.
I hope it can return 11100001 as char.
//xor
char * xorencrypt(char * a, char * b) {
size_t alen = strlen(a);
size_t blen = strlen(b);
char * encrypted = malloc(alen + 1);
int i;
for (i = 0; i < 8; i++) {
encrypted[i] = a[i] ^ b[i];
printf("%s\n", encrypted[i]);
}
encrypted[alen] = '\0';
return encrypted;
}
main {
char * char_str = xorencrypt("11011000", "00111001");
printf("%s\n", char_str);
}
Your code needs a bit of refactoring.
1) You need to include some headers
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2) the 'main' function should return an int
int main() {
/* code here */
return 0;
}
3) You should make sure the call to malloc succeeds
char * encrypted = malloc(alen + 1);
assert(encrypted != (char*)0); /* requires #include <assert.h>
4) You should be careful when xor'ing ones and zeros. You are handling chars like integers
you are xoring zeros (value 48 in ascii) with ones (value 49 in ascii)
encrypted[i] = a[i] ^ b[i];
you want something like this instead
int a_i = a[i] - '0';
int b_i = b[i] - '0';
encrypted[i] = (a_i ^ b_i) + '0';
A reworked version of the code that assumes you are dealing exclusively with strings of the binary digits '0' and '1'. If you are dealing with more general strings, you will need a different solution.
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static
char *xorencrypt(char *a, char *b)
{
size_t alen = strlen(a);
char *encrypted = malloc(alen + 1);
assert(alen == strlen(b));
assert(encrypted != NULL);
for (size_t i = 0; i < alen; i++)
{
assert(a[i] == '0' || a[i] == '1');
assert(b[i] == '0' || b[i] == '1');
encrypted[i] = (a[i] ^ b[i]) + '0';
putchar(encrypted[i]);
}
encrypted[alen] = '\0';
putchar('\n');
return encrypted;
}
int main(void)
{
char *char_str = xorencrypt("11011000", "00111001");
printf("%s\n", char_str);
free(char_str);
return 0;
}
Amongst the changes:
Error check the memory assignment. Using assert() is a bad way to do it in production code, but it does ensure that you check that the memory is allocated.
Check that the strings are the same length.
Remove unused variable blen.
The static is optional; it means the code compiles cleanly under the stringent options I use (which require a prototype declaration of every non-static function before it is defined or used).
The loop index i is of the same type size_t as alen to avoid warnings about comparing signed and unsigned values. I'm using the C99 style 'declare a variable in a for loop' notation.
The upper bound of the loop is based on the measured length of the strings, not a fixed constant.
The original version of the XOR operation either generated a null '\0' or a control-A '\1' for each character.
The revised version of the crucial XOR operation ensures that the result is a printable digit.
The printf("%s\n", encrypted[i]); in the original passed a character to be printed as a string. If your compiler wasn't warning you, turn on the warning options or get a better compiler.
If you'd written printf("%s\n", &encrypted[i]); you would have had problems, potentially, with a string that is not guaranteed to be null terminated inside the loop (though you did null terminate the string after the loop, which was good).
The code in main() frees the allocated memory. It is good practice to ensure there is a free() for every malloc().
I prefer to explicitly return 0 from main(), even though C99 says you don't have to.
This answer was started while the question was active. Then life got in the way.

c - dereferencing issue

I have simplified an issue that I've been having trying to isolate the problem, but it is not helping.
I have a 2 dimensional char array to represent memory. I want to pass a reference to that simulation of memory to a function. In the function to test the contents of the memory I just want to iterate through the memory and print out the contents on each row.
The program prints out the first row and then I get seg fault.
My program is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
void test_memory(char*** memory_ref) {
int i;
for(i = 0; i < 3; i++) {
printf("%s\n", *memory_ref[i]);
}
}
int main() {
char** memory;
int i;
memory = calloc(sizeof(char*), 20);
for(i = 0; i < 20; i++) {
memory[i] = calloc(sizeof(char), 33);
}
memory[0] = "Mem 0";
memory[1] = "Mem 1";
memory[2] = "Mem 2";
printf("memory[1] = %s\n", memory[1]);
test_memory(&memory);
return 0;
}
This gives me the output:
memory[1] = Mem 1
Mem 0
Segmentation fault
If I change the program and create a local version of the memory in the function by dereferencing the memory_ref, then I get the right output:
So:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
void test_memory(char*** memory_ref) {
char** memory = *memory_ref;
int i;
for(i = 0; i < 3; i++) {
printf("%s\n", memory[i]);
}
}
int main() {
char** memory;
int i;
memory = calloc(sizeof(char*), 20);
for(i = 0; i < 20; i++) {
memory[i] = calloc(sizeof(char), 33);
}
memory[0] = "Mem 0";
memory[1] = "Mem 1";
memory[2] = "Mem 2";
printf("memory[1] = %s\n", memory[1]);
test_memory(&memory);
return 0;
}
gives me the following output:
memory[1] = Mem 1
Mem 0
Mem 1
Mem 2
which is what I want, but making a local version of the memory is useless because I need to be able to change the values of the original memory from the function which I can only do by dereferencing the pointer to the original 2d char array.
I don't understand why I should get a seg fault on the second time round, and I'd be grateful for any advice.
Many thanks
Joe
Try:
printf("%s\n", (*memory_ref)[i]);
The current version is equivalent to
*(*(memory_ref + i));
This is because the [] operator has higher precedence than the dereference *. Which means that when i is larger than 0 you try to read memory after the char*** temporary memory_ref
The second version is equal to (*memory_ref)[i] which means that you will be indexing the correct memory.
EDIT: The reason it works on the first iteration is because:
*(*(memory_ref + 0)) == *((*memory_ref) + 0)
This looks like a precedence issue. The [] is getting evaluated first, and the * second. What you would need is something like the following for your first code example ...
printf("%s\n", (*memory_ref)[i]);
The quick fix is to use
printf("%s\n", (*memory_ref)[i]);
But I suspect you have an problem in the lines
memory[0] = "Mem 0";
These do not copy the string "Mem 0" into your memory array. They make memory[i] point to the string.
You need to explicitly copy the data using strncpy
e.g.
char s = "Mem 0";
strncpy( memory1, s, max( strlen(s) + 1, 29) ) // max of 30= (29 char + '\0' as that is the row length you allocated - better to #define this as a constant

Resources