Swap between array of strings only by pointers in C - c

I need to plot a function that receives an array of pointers (to strings) and sort the pointers by length of string. The shortest string will be in the first place, and so on. I tried the following code but it doesn't work:
void Q5(){
char str[MAXL][MAXC];
int i;
char** p;
printf("Please enter %d Strings max length = %d\n",MAXL,MAXC);
for (i = 0; i < MAXL; i++){
scanf("%s", str[i]);
}
p = &str;
sort_String(p,MAXL);
printf("\n");
for (i = 0; i < MAXL; i++){
printf("%s", str[i]);
printf("\n");
}
}
void sort_String(char* str,int size){
char* tempP=*str;
char* i,*j;
for (i=str; i < str+size;i++){
for (j=i+1; j < str+size; j++){
if (strlen(i) > strlen(j)){
tempP = j;
j = i;
i = tempP;
}
}
}

An array of pointers is not the same string as a 2D array, even if they are used the same to get a value. To be able to swap strings, you must have an array of pointers. Here is a commented quickfix to your code, because you were not that far from it:
void Q5(){
char str[MAXL][MAXC]; // Ok a 2D array is nice to read the string
int i;
char* p[MAXL]; // the array of MAXL pointers
printf("Please enter %d Strings max length = %d\n",MAXL,MAXC);
for (i = 0; i < MAXL; i++){
scanf("%s", str[i]); // the string is read
p[i] = str[i]; // and the array of pointers is initialized
}
sort_String(p,MAXL);
printf("\n");
for (i = 0; i < MAXL; i++){
printf("%s", p[i]); // only p has been sorted, str is unchanged
printf("\n");
}
}
void sort_String(char** str,int size){ // takes an array of pointers as first parameter
char* tempP;
int i, j;
for (i=0; i < size;i++){ // ok for a bubble sort
for (j=i+1; j < size; j++){
if (strlen(str[i]) > strlen(str[j])){ // compare length of pointed strings
tempP = str[j]; // swap
str[j] = str[i];
str[i] = tempP;
}
}
}
I assumed that MAXL and MAXC were both constant values (#define)

To achieve what you said you should dynamically malloc the necessary part then you can use this code. But you can't change a arrays positions(locations) That is not allowed.
// L-> number of strings
// C-> character needed
char **str=malloc(sizeof(char*)*L);
for(i=0;i<MAXL;i++)
str[i]=malloc(sizeof(char)*C);
Then you can simply apply the bubble sort that you have written.
You need to pass the char** in sorting function.
Iterating over the pointer variables in sort function is not needed. If you allocate dynamically as I have mentioned then you can code it this way:-
void sort_String(char** str,int size)
{
char* tempP;
int i,j;
for (i=0; i < size;i++){
for (j=i+1; j < size; j++){
if (strlen(str[i]) > strlen(str[j])){
tempP = str[j];
str[j ]= str[i];
str[i] = tempP;
}
}
}
}
There are few issues though like you have not given a proper code there is error like Q5()'s } is missing. Give MCV example.
Note: I assumed that you are using a c compiler. That's why I have avoided the casting. In C, you don't need to cast the return value of malloc. The pointer to void returned by malloc is automatically converted to the correct type. However, if you want your code to compile with a C++ compiler, a cast is needed.

Related

Possible to run through a c-array inside a function with only one pointer as parameter?

I'm playing and learning a little with C, created an array and passed it to a function together with its size so I can run through the array and print all its elements (so I gave the function two parameters: the array itself and its size).
But now I like to do all that just by passing one parameter to the function. I got it working a little by using a pointer but I don't know how to stop because I don't have any information about arrays length, it only works in the code below because I put the array length inside the for loop. But how would that work in general if I didn't know the size and only passed one parameter to the function?
I thought it might somehow be possible to realize if a pointer points outside of the array I'm currently working with, but is that even doable? :S
void printArray(int *p){
for(int i=0; i<4; i++){
printf("%d ", *(p+i));
}
}
int main(){
int myArray[4] = {8,4,1,1};
int *p = myArray;
printArray(p);
return 0;
}
The only way to traverse a pointed-to array without a length parameter is if the array contains a distinct terminator value.
For example, a C-string is "NULL-terminated" array of char values. You can traverse a char* because you know
to test for the presence of the '\0' character, which has an integer value of 0.
As it applies to the code in your question, you could use -1 as a terminator value, like so:
void printArray(int *p){
while (*p != -1{
printf("%d ", *p++);
}
}
Note however, that doing this requires that there is some way to interpret a valid int value as
"invalid" for your purposes.
In the main, it's much easier and simpler to just pass the length of the array to the function.
In addition to other mentioned approaches I can offer other two:
1) You can pass the length of array as the first element (like works some containers in Pascal):
#include <stdio.h>
void print_array(int *arr)
{
int length = arr[0];
for (int index = 1; index <= length; ++index)
printf("%d ", arr[index]);
printf("\n");
}
int main()
{
int length = 10;
int *arr = malloc(sizeof(int) * length);
arr[0] = length;
for (int index = 1; index <= length; ++index)
arr[index] = index * index * index;
print_array(arr);
free(arr);
return 0;
}
2) You can create a struct for your array (like is is done for std::vector in C++ STD with class):
#include <stdio.h>
typedef struct Array
{
int size;
int *data;
} Array;
void print_array(Array *arr)
{
for (int index = 0; index < arr->size; ++index)
printf("%d ", arr->data[index]);
printf("\n");
}
int main()
{
int length = 10;
Array *arr = malloc(sizeof(Array));
arr->data = malloc(sizeof(int) * length);
arr->size = length;
for (int index = 0; index < length; ++index)
arr->data[index] = index * index * index;
print_array(arr);
free(arr->data);
free(arr);
return 0;
}

Remove members from an array of char *

I've written this function to remove count members from arr at index idx.
void remove_int(int (*arr)[], int idx, int count)
{
int i, j;
for (i = 0; i < count; i++)
for (j = idx; (*arr)[j]; j++)
(*arr)[j] = (*arr)[j+1];
}
I call it like this:
remove_int(&arr, index, cnt);
This works perfectly for local integers. Here's my problem. I have a header file like this:
struct {
/* other stuff */
char *array[100];
} global_struct;
Members in array are allocated and filled.
Someone figured I could just switch int to char and int (*arr)[] to char *(*arr)[], then call:
remove_char(&global_struct.array, index, cnt);
I tried it, but it doesn't actually modify global_struct.array. How should I change remove_int to work with global_struct.array?
global_struct.array is a pointer to char, and looks like it is intended to point to a string. So you need to change the function signature to something like:
void remove_strings(char *str[], size_t idx, size_t count);
I would suggest changing idx, count, i, and j to type size_t, as this is an unsigned integer type guaranteed to hold any array index. The size_t type has been available since C99.
Here is a demonstration program that incorporates a modified version of the remove_int() function:
#include <stdio.h>
struct {
char *array[100];
} global_struct;
void remove_strings(char *str[], size_t idx, size_t count);
int main(void)
{
global_struct.array[0] = "One";
global_struct.array[1] = "Two";
global_struct.array[2] = "Three";
global_struct.array[3] = "Four";
global_struct.array[4] = "Five";
global_struct.array[5] = NULL;
for (size_t i = 0; global_struct.array[i]; i++) {
printf("%s\n", global_struct.array[i]);
}
remove_strings(global_struct.array, 2, 2);
putchar('\n');
puts("After removal:");
for (size_t i = 0; global_struct.array[i]; i++) {
printf("%s\n", global_struct.array[i]);
}
return 0;
}
void remove_strings(char *str[], size_t idx, size_t count)
{
size_t i, j;
for (i = 0; i < count; i++)
for (j = idx; str[j]; j++)
str[j] = str[j+1];
}
Program output:
One
Two
Three
Four
Five
After removal:
One
Two
Five
Also, it appears that your function remove_int() only works on arrays of int that exclude 0 members, as 0 is used as a sentinel value in the inner loop of your function. It is common to terminate an array of pointers to char with a NULL pointer, as I have done, and of course a string is an array of chars terminated with a '\0'. But, it is not in general a good idea to terminate an array of ints with a zero. This feature of your code did make it a simple matter to adapt it to work with strings.
While your function may satisfy your current requirements, consider changing it to return the number of ints stored in the array. It makes sense to keep track of the number of ints stored in the array, and passing this value as an argument allows the function to iterate over the array without a sentinel value. Here is a revised version of your function:
size_t remove_ints(size_t idx, size_t count, int arr[], size_t arr_sz)
{
size_t i, j;
for (i = 0; i < count; i++)
for (j = idx; j < arr_sz; j++)
arr[j] = arr[j+1];
return arr_sz - count;
}
The purpose of "for (i = 0; i < count; i++)"?
As my understand I think you should:
void remove_int(int (*arr)[], int idx)
{
int j;
for (j = idx; (*arr)[j]; j++)
(*arr)[j] = (*arr)[j+1];
}

Pass char** as an argument to a function in C

I know there are many topics of this kind but I've read several of them and still can't figure out what am I doing wrong.
I've successfully generated a char** array. My bubble sort function probably works as well. But when I passed the generated array to the function, only 1 row is copied.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
void sort(char** tab)
{
char* temp;
int i, j, size = sizeof(tab)/sizeof(tab[0]);
printf("%d\n", size);
for(i = 0; i < size; ++i)
{
for(j = i+1; j < size; ++j)
{
if(strcmp(tab[j-1], tab[j]) > 0)
strcpy(temp, tab[j-1]),
strcpy(tab[j-1], tab[j]),
strcpy(tab[j], temp);
}
}
for(i = 0; i < sizeof(tab)/sizeof(tab[0]); ++i)
puts(tab[i]);
}
int main()
{
srand(time(NULL));
int size = rand()%5+5, i, j, s;
char** tab = (char**)malloc(size * sizeof(char*));
for(i = 0; i < size; ++i)
{
s = rand()%9+1;
tab[i] = (char*)malloc(s+1);
for(j = 0; j < s; ++j)
tab[i][j] = 'a'+rand()%26;
tab[i][s] = 0;
}
for(i = 0; i < size; ++i)
puts(tab[i]);
puts("");
sort(tab);
return 0;
}
Here's how the code works.
And when I write size=5 before the loop in the function it returns segmentation fault.
Edit: Same with passing the size of the array as an argument:
http://ideone.com/3Wvncq
Final code
I've fixed all the problems and here's the final code.
I was misinterpreting segmentation fault as the result of assigning a fixed size instead of not allocating the temp variable.
Thank you for all the answers.
Don't calculate size inside function void sort(char** tab) . As in this function it will be calculated as -
int i, j, size = sizeof(tab)/sizeof(tab[0]); // equivalent to sizeof(char **)/sizeof(char*) in function giving wrong length as you desire.
It's length in main(size is generated using rand so no need to find it) and then pass it as argument to function sort.
Declare your function like this -
void sort(char** tab,size_t size)
And while calling from main pass length of tab to it -
sort(tab,size); // size will be number of elements in tab calculated in main
You get segmentation fault because of this -
if(strcmp(tab[j-1], tab[j]) > 0)
strcpy(temp, tab[j-1]),
strcpy(tab[j-1], tab[j]),
strcpy(tab[j], temp);
temp is uninitialized in sort and still you pass it to strcpy thus undefined behaviour . Initialize temp before passing to strcpy.Allocate memory to temp in function sort.
In your sort function you declare the temp variable:
char* temp;
Later you use it as destination (and source) for string copying:
strcpy(temp, tab[j-1]),
But nowhere in between do you make temp point anywhere, temp is uninitialized and that leads to undefined behavior and your crash.
Don't use a pointer, instead declare it as an array of the largest string size possible.

whats going wrong with my program?

the program is supposed to compare the strings and place them in alphabetical order, but the final printf statement prints garbage...where am i going wrong here?
i have used an array of pointers to strings and declared them in the begining, i have even tried using temp as an array rather than pointer stil doesnt quite work
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int j;
int i;
char *temp;
char *string[5] = {"ibrahim","laura","peter","degea"};
for ( i = 0; i< 4;i++)
printf("%s\n", string[i]); //allocating memory
for( i = 0; i< 10 ;i++)
string[i] = (char*)malloc (30 * sizeof(char));
temp = (char*)malloc(30*sizeof(char));
for ( i=0; i< 3; i++)
for(j =i+1; j<4; j++)
{
if(strcmp(string[i], string[j]) > 0)
{
strcpy(temp, string[i]);
strcpy(string[i], string[j]);
strcpy(string[j], temp);
}
}
for (i = 0; i< 4; i++)
{
printf("%s\n",string[i]);
puts("\n");
}
free(string);
free(temp);
return 0;
}
string[i] = (char*)malloc (30 * sizeof(char));
This is overwriting the existing initialized values.
EDIT
for( i = 0; i< 10 ;i++)
temp = (char*)malloc(30*sizeof(char));
WHAT? you are allocating memory over and over 10 times on a single pointer?
EDIT 2:
The original post is lost (read Edited). By the time you are reading this answer, both Mr. Jonathan Leffler and this poster migh look like absolute fools in this world.
The code originally destroyed its data array (by allocating new pointers). Now it seems to throw memory away by allocating temp four times (but Jeevan's edit reinstates the old code in indented form). The old code allocated space for strings but never initialized them (having thrown away the value that was in the array beforehand).
NB: any commentary on the code could easily be invalid by the time you're reading the commentary — the code in the question could have changed.
for (i = 0; i < 10; i++)
string[i] = malloc(30);
This code tramples out of the bounds of the string array (dimension is 5). It also loses the data originally in the array.
You need to use strcmp() to compare the strings, but you simply need to swap pointers rather than using strcpy() at all.
The comment // allocating memory beside a printf() statement is misleading, too.
This stands a chance of working. Note that there is no memory allocation:
#include <stdio.h>
#include <string.h>
int main(void)
{
int j;
int i;
char *string[] = { "ibrahim", "laura", "peter", "degea" };
for (i = 0; i < 4; i++)
printf("%s\n", string[i]);
for (i = 0; i < 3; i++)
{
for (j = i+1; j < 4; j++)
{
if (strcmp(string[i], string[j]) > 0)
{
char *temp = string[i];
string[i] = string[j];
string[j] = temp;
}
}
}
for (i = 0; i < 4; i++)
printf("%s\n",string[i]);
return 0;
}
Output:
ibrahim
laura
peter
degea
degea
ibrahim
laura
peter
Comment: don't try sorting thousands of strings using this sort algorithm.
You are overwriting the existing string array contents with malloc, that too 10 times.
Please use braces in your code for better understanding
for( i = 0; i< 10 ;i++)
string[i] = (char*)malloc (30 * sizeof(char));
temp = (char*)malloc(30*sizeof(char));
can be written as
for( i = 0; i< 10 ;i++) // why to allocate memory ten times, that too overwriting
{
string[i] = (char*)malloc (30 * sizeof(char));
}
temp = (char*)malloc(30*sizeof(char));
when you declare :
char *string[5] = {
"ibrahim",
"laura",
"peter",
"degea" };
the pointer *string[0] to *string[3] allocated to a address in the memory, where will stored the init values "ibrahim","laura"...
when you use malloc function for the pointer string[i] = (char*)malloc (30 * sizeof(char));
the pointer *string[0] to *string[4] will be allocated to another address in the memory. so the value at these address are different from that you initialized (ibrahim,laura).
you should use static array instead dynamic as below
char temp;
char string[5] = {
"ibrahim",
"laura",
"peter",
"degea" };
remove all the malloc, free function.

find number of rows in a 2D char array

How to find number of rows in dynamic 2D char array in C?
Nothing from there.
tried with following code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int k = 97;
void foo(char **a)
{
int i = 0;
for(i=0; a[i] != NULL; ++i)
printf("i = %d\n", i);
}
void strcpyo(char* a, char*b){
int i=0;
for(i=0;b[i]!='\0';i++){
a[i]=b[i];
}
a[i]='\0';
}
void strcpym(char* a, char*b){
int i=0;
for(i=0;b[i]!='\0';i++);
memcpy(a,b,i+1);
}
void freee(char** ptr){
int i;
for(i = 0;i < k; ++i)
{
free(ptr[i] );
}
free(ptr);
}
void alloc(char ***p)
{
*p = (char **)malloc(k * sizeof(char *));
int i,j;
for(j=0;j<k;j++)
{
// for(i = 0;i < j; ++i)
{
(*p)[j] = (char *)malloc(11 * sizeof(char));
strcpy((*p)[j],"paicharan");
}
//printf("j = %d ", j);
//foo(p);
}
}
int main()
{
char **p;
alloc(&p);
#if 0
char **p = (char **)malloc(k * sizeof(char *));
int i,j;
for(j=0;j<k;j++)
{
for(i = 0;i < j; ++i)
{
p[i] = (char *)malloc(11 * sizeof(char));
strcpy(p[i],"paicharan");
}
printf("j = %d ", j);
foo(p);
}
#endif
foo(p);
freee(p);
return 0;
}
The code in #if 0 #endif works perfectly, but if I do create arrays in function alloc(char**) it's giving the wrong answer for odd number of rows in array. Can anybody explain why?
ie. for k= odd number it gives out wrong answer but for even number its correct.
Your code depends on Undefined Behaviour to work correctly i.e. it'll work only by chance. This has got nothing to do with even or odd count of elements.
In the void alloc(char ***p) function you allocate memory for k pointer to pointer to char: char**. Then you fill all of the k pointers with new valid char* pointers i.e. none of them are NULL. Later in void foo(char **a) you do for(i=0; a[i] != NULL; ++i); since a[k - 1] was non-null, it'll iterate over them correctly. BUT after that a[k] may or may not be NULL, you never know what is in there. Also accessing what is beyond the array you allocated is undefined behaviour (due to out of bounds access).
Making k + 1 elements and setting the kth element to NULL makes this work; make sure you free all of k + 1 elements and not leak the last sentinal element.
Since you told that the code wraped inside the macro works fine, I've ignored that; don't know if there's UB there too. If you're doing this exercise to learn, it's fine. If you are planning to do some other project, try to reuse some existing C library which already gives these facilities.

Resources