strcpy() generates segmentation fault on variable sized array of strings - c

I'm learning "C" language, I have created a program as below that would copy command-line arguments to another variable sized array (of strings) and print that array starting from index 2.
#include <stdio.h>
#include <string.h>
void print_array(const char* arr[]) {
for (int i = 0; arr[i]; i++) {
printf("%s\n", arr[i]);
}
}
void copy_array(char* dest[], const char* src[]) {
for (int i = 0; src[i]; i++) {
strcpy(dest[i], src[i]);
}
}
int main(int argc, const char* argv[]) {
if (argc < 2)
return 1;
char args[argc][256];
copy_array(args, argv);
print_array(&args[2]);
return 0;
}
The problem is, when I call it via './a.out one two three four five', it throws a segmentation fault. Using gdc, I could see that strcpy() did this. I'm just learning it, can't really find the cause. Can someone point me to what I'm doing wrong?

Your problem is that an array of arrays of char is not the same as an array of pointers to char. That may seem pedantic, but underlying structure is different.
In fact, your compiler should be issuing a warning (if it's not, you should increase your warning levels).
More specifically, if a is an array of array of chars, then a[i] is an address relative to the start of your array that can only be calculated because the compiler knows how large each sub array is (e.g. 256 in your case).
Whereas, if a is an array of pointers to char, no calculation is required, a[i] contains the value of the pointer itself.
By passing an array of arrays where an array of pointers is expected, you are causing the compiler to calculate the address incorrectly (i.e. undefined behavior) and hence your segfault.
If you want to be consistent and use an array of pointers everywhere, your code might look more like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void print_array(char* arr[]) {
for (int i = 0; arr[i]; i++) {
printf("%s\n", arr[i]);
}
}
void copy_array(char* dest[], char* src[]) {
int i;
for (i = 0; src[i]; i++) {
dest[i] = malloc(strlen(src[i]) + 1);
strcpy(dest[i], src[i]);
}
dest[i] = NULL;
}
int main(int argc, char* argv[]) {
if (argc < 2)
return 1;
char *args[argc + 1];
copy_array(args, argv);
print_array(&args[2]);
return 0;
}

It seems the copy_array loop execute after the actual length of the array
void copy_array(char* dest[], const char* src[]) {
for (int i = 0; src[i]; i++) {
strcpy(dest[i], src[i]);
}
}
should be changed to
void copy_array(char* dest[], const char* src[], int count) {
for (int i = 0; i < count; i++) {
strcpy(dest[i], src[i]);
}
}
Also print array should be changed to:
void print_array(const char* arr[], int count) {
for (int i = 0; i < count; i++) {
printf("%s\n", arr[i]);
}
}

Related

Null pointer using const instead of variable declaration

I have a problem I can't figure out. I wrote this code to shuffle the elements of an array:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
const char *array[]={"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};
int main(int argc, char **argv)
{
int i, tmp, randomize, size;
size = sizeof(array)/sizeof(*array);
srand(time(NULL));
for(i=size;i>0;i--){
randomize=0+(rand()%size);
tmp=(int)array[i];
array[i]=array[randomize];
array[randomize]=(char*)tmp;
}
for(i=0;i<size;i++)
printf("%s", array[i]);
return 0;
}
When I run the program, this is the iutput:
azlngiwexbv(null)uscphqjyrodmtk
I can't understand why the pointer is sometimes null and I can't understand why, changing the source code in this way:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char **argv)
{
char *array[]={"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};
int i, tmp, randomize, size;
size = sizeof(array)/sizeof(*array);
srand(time(NULL));
for(i=size;i>0;i--){
randomize=0+(rand()%size);
tmp=(int)array[i];
array[i]=array[randomize];
array[randomize]=(char*)tmp;
}
for(i=0;i<size;i++)
printf("%s", array[i]);
return 0;
}
Everything works fine.
Thanks.
Start loop from size-1, you are pointing out of array in array[size] (first loop iteration).
for (i=size-1; i>=0; i--)
You should avoid casting whenever possible, and it is rarely necessary to do so.
Unless you plan on using argc and argv[], use the simpler form for main(): int main(void). This will remove some compiler warnings, and you should have these enabled; remove all warnings emitted by your compiler.
You cast a pointer to char to int to store it in tmp, and then you cast tmp back to (char *). Just declare tmp as a pointer to char to start with. The first loop counts down from size to 0; this is out of array bounds to start, but why not just use the conventional loop construction: for (i = 0; i < size; i++)? Also, you should consider using size_t for array indices; it is an unsigned integer type guaranteed to be able to hold any array index, and is also the type returned by the sizeof operator.
Further, in your first version you have declared array as an array of pointers to const chars. You can do this, but you need the temporary storage variable tmp to agree with the const type qualifier.
Here is your code with the above changes. There are no casts, it compiles without warnings, and it works.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
const char *array[] = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};
const char *tmp;
size_t i, size;
int randomize;
size = sizeof(array) / sizeof(*array);
srand(time(NULL));
for(i = 0; i < size; i++){
randomize = (rand() % size);
tmp = array[i];
array[i] = array[randomize];
array[randomize] = tmp;
}
for(i = 0; i < size; i++)
printf("%s", array[i]);
putchar('\n');
return 0;
}

Initialization and increment of array of pointers to integers

I have written the following code in C for initializing and increment an array of pointers to int.
#include <stdio.h>
#include <stdlib.h>
int * arr;
void initArray (int *arr, int size) {
arr = malloc(sizeof(int)*size);
for (int i=0; i< size; i++) {
arr[i]= i;
printf("%d ", arr[i]);
}
printf("\n");
}
void incArray(int *arr, int size) {
for (int i=0; i< size; i++) {
arr[i]= i+1;
printf("%d ", arr[i]);
}
printf("\n");
}
void main(){
initArray(arr, 3);
incArray(arr, 3);
}
Unless I use malloc in both functions, the program (when run) gives this error:
Running "/home/ubuntu/workspace/hello-c-world.c"
0 1 2
bash: line 12: 93714 Segmentation fault "$file.o" $args
Process exited with code: 139
Not sure why once the initArray function is called why it needs memory allocation again in increment function. I am assuming it's treating the array for the second function as a separate one whereas I want to increment the values in the first array that initArray function creates.
I'd really appreciate being pointed in the right direction.
You want this:
#include <stdio.h>
#include <stdlib.h>
void initArray (int **arr, int size) {
*arr = malloc(sizeof(int)*size);
for (int i=0; i< size; i++) {
(*arr)[i]= i;
printf("%d ", (*arr)[i]);
}
printf("\n");
}
void incArray(int *arr, int size) {
for (int i=0; i< size; i++) {
arr[i]= i+1;
printf("%d ", arr[i]);
}
printf("\n");
}
void main(){
int *arr;
initArray(&arr, 3); // << this will modify arr
incArray(arr, 3);
}
In your code, you have two variables whose name is arr : one is inside the global scope, and the other one is in initArray function scope. Look at this instruction inside initArray :
arr = malloc(sizeof(int)*size);
As function's local scope is resolved before global's one in C language, it's the arr parameter of the function which is going to store the allocation, not the global arr variable. And as you're returning nothing, this pointer will be destroyed at the end of your function, and you will not have any access to your allocation anymore. And so, the global arr will never be modified and its value will always be NULL or an undefined value.
This is why, inside incArray when you're doing this writing instruction...
arr[i]= i+1;
... you are actually trying to write i + 1 in a NULL or undefined address, which is not an address your processus has the right to write in, causing this segmentation fault.
A simple fix would be to return the pointer in initArray and to store it in your global arr variable, like that:
int * arr;
int* initArray (int size) {
int* arr = malloc(sizeof(int)*size);
// ...
return arr;
}
void incArray(int *arr, int size) {
// ...
}
void main(){
arr = initArray(3);
incArray(arr, 3);
}
The arr in initArray() is hiding the global arr, and modifications made to arr in initArray() are not made to the global arr. Your code then calls incArray() with the (unmodified) global arr — which is still a null pointer. This gives you a seg fault when you try to use it. It also means that you leak the memory when the function returns.
You'll need to work out whether you want the global variable or not — I suggest removing it. Global variables should be avoided when possible.
You will need to change the signature of the initArray() function — there are (at least) two options.
Option 1 — Return pointer to allocated space
You could change initArray() to return a pointer to the allocated space. It would have the signature int *initArray(int size) and you'd call it as:
int *arr = initArray(3);
This yields:
#include <stdio.h>
#include <stdlib.h>
int *initArray(int size)
{
int *arr = malloc(sizeof(int)*size);
if (arr != 0)
{
for (int i = 0; i < size; i++)
{
arr[i] = i;
printf("%d ", arr[i]);
}
printf("\n");
}
return arr;
}
void incArray(int *arr, int size) // Unchanged
{
for (int i = 0; i < size; i++)
{
arr[i] = i+1;
printf("%d ", arr[i]);
}
printf("\n");
}
int main(void)
{
int *arr = initArray(3);
if (arr != 0)
incArray(arr, 3);
return 0;
}
Where I compare to 0, you may prefer to compare to NULL. Note that the code is careful to check that allocations succeed before using the allocated space.
Option 2 — Pass a pointer to a pointer
Alternatively, if you like double pointers, you can pass a pointer to a pointer to the function:
void initArray(int **arr, int size)
{
*arr = malloc(sizeof(int) * size);
if (*arr != 0)
{
for (int i = 0; i < size; i++)
{
(*arr)[i] = i;
printf("%d ", (*arr)[i]);
}
printf("\n");
}
}
// incArray unchanged again
int main(void)
{
int *arr;
initArray(&arr, 3);
if (arr != 0)
incArray(arr, 3);
return 0;
}

How should I implement a rollDice() function in C?

I try to implement a function meant to roll a dice a certain amount of time.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int * rollDice(int len) //len = times the dice is rolled.
{
int ints[len];
int i = len-1;
while(i>0)
{
ints[i--] = (rand()%6)+1;
}
return ints;
}
int main(int argc, const char * argv[])
{
int * ints = rollDice(10);
for(int i =0; i<10; i+=1)
{
printf("%d ",*(ints+i));
}
return 0;
}
Program always prints this, is my conception of pointers false ?
104 0 0 0 1919706998 2036950640 1667723631 1836545636 16 48
You cannot do this
return ints;
It's declared on the stack. You need to either pass it in with enough memory or allocated the memory in the function using malloc and pass it back.
int * rollDice(int len) //len = times the dice is rolled.
{
int *ints = malloc(sizeof(int) * len);
int i = len-1;
while(i>0)
{
ints[i--] = (rand()%6)+1;
}
return ints;
}
Harry's answer is right; you can't return the address of a local variable. That variable is destroyed as soon as the function returns.
Instead of having to allocate memory in the function, just pass the array to be filled into the function:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM_DICE 10
void rollDice(int *dice, int num_dice)
{
int i;
for (i = 0; i < num_dice; i++) {
dice[i] = (rand() % 6) + 1;
}
}
int main(int argc, const char * argv[])
{
int dice[NUM_DICE];
srand(time()); /* Don't forget this! */
rollDice(&dice, NUM_DICE);
for(int i = 0; i < NUM_DICE; i++)
{
printf("%d ", dice[i]); /* Easier to use brackets than pointer arithmetic. */
}
return 0;
}

C Programming EXC_BAD_ACCESS on very basic C program

I am quite new to C programming. I need to write a programm that works with dynamic Arrays. (Takes in Values and doubles the size of the Array, when it is full). My programm is finished and compilation works but I keep on getting this Error in the commented line: Thread 1: EXC_BAD_ACCESS (code=2, address:(some long adress).
I have read on this and it seems that I may be pointing to null. But a null test didn't do the job. I'Ve had this problem in other programms before and I seem to be missing a basic point.
Can somebody help me with this please!
This is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int *value;
int size;
int MAX;
} DynArray;
void dyn_array_add (DynArray* array){
int wert;
int *temp;
printf("Geben Sie einen Wert ein:\n");
scanf("%i", &wert);
if (array->MAX==array->size) {
for (int i= 0; i<array->MAX; i++) {
temp[i] = array->value[i]; // error occurs HERE
}
free(array->value);
array->MAX = array->MAX*2;
array->value=malloc(sizeof(int)* array->MAX);
for (int i= 0; i<array->MAX; i++) {
array->value[i] = temp[i];
}
}
array->value[array->size]= wert;
array->size++;
for (int i = 0; i < array->MAX; i++) {
printf("Value[%i]: %i \n", i, array->value[i]);
}
}
int main(int argc, const char * argv[]) {
DynArray* array;
array = (DynArray*)malloc(sizeof(DynArray));
array->MAX=5;
array->size=0;
array->value=malloc(sizeof(int)* array->MAX);
while (1) {
dyn_array_add(array);
}
return 0;
}
temp[i] = array->value[i]; // error occurs HERE
Obviously, because you have not allocated memory for temp.

Issues with passing pointer arrays and printing them

I'm having some issues with very simple situations of passing arrays as pointers into functions and returning them. I thought I had pointers figured but I just can't get my head around it.
Here's the code:
int* getLottoDraw();
void printArray(int * array);
int find_matches(int * array1, int * array2);
int main(int argc, char *argv[])
{
int * lotteryDraw = getLottoDraw();
printArray(lotteryDraw);
system("PAUSE");
return 0;
}
int* getLottoDraw(){
int draw[6];
int i;
srand(time(NULL));
for (i = 0; i < 6; i++) {
int r = rand() % 49;
draw[i] = r;
}
return draw;
}
void printArray(int *array){
int i;
for (i = 0; i < 6; i++){
printf("%i ", array[i]);
}
}
One example output is "3 2047 4614546 0 25 45". Not what was hoping for.
You are returning a stack address, which end up being destroyed when the function ends.
Stack variables are local variables, their scope is limited to the function they're created.
They're created on the function, and destroyed when the function ends, so if you've try to access this address later you'll get undefined behavior.
You should have a dynamic allocated pointer to be able to access it outside the function, or return by value, copying the content (which can be costly in an array case).
You could do something like:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int* getLottoDraw();
void printArray(int * array);
int find_matches(int * array1, int * array2);
int main(int argc, char *argv[])
{
int * lotteryDraw = getLottoDraw();
printArray(lotteryDraw);
free(lotteryDraw);
return 0;
}
int* getLottoDraw(){
int* draw = malloc(sizeof(int)*6);
int i;
srand(time(NULL));
for (i = 0; i < 6; i++) {
int r = rand() % 49;
draw[i] = r;
}
return draw;
}
void printArray(int *array){
int i;
for (i = 0; i < 6; i++){
printf("%i ", array[i]);
}
}

Resources