I am trying to solve a C problem where I have to sort n strings of characters using pointers.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sort (char *s, int n)
{
int i,j; char aux[]="";
for (i=1;i<=n-1;i++)
{
for (j=i+1;j<=n;j++) //if s[i]> s[j] switch
{
if (strcmp(*(s+i),*(s+j))==1)
{
strcpy(aux,*(s+i);
strcpy(*(s+i),*(s+j));
strcpy(*(s+j),*(s+i));
}
}
}
}
void show(char *s, int n)
{
int i;
for (i=1;i<=n;i++)
{
printf("%s",*(s+i));
}
}
int main()
{
int i,n; char *s;
printf("give the number of strings:\n");
scanf("%d",&n);
s=(char*)calloc(n,sizeof(char));
for (i=1;i<=n;i++)
{
printf("s[%d]= ",i);
scanf("%s",s+i);
}
sort(s,n);
show(s,n);
return 0;
}
The warnings that I get are when I use strcmp to compare and when I use strcpy to switch *(s+i) and *(s+j) values.
"passing argument 2 of strcmp makes pointer from integer without a cast"
The warnings that I get are when I use strcmp to compare and when I use strcpy to switch *(s+i) and *(s+j) values.
"passing argument 2 of strcmp makes pointer from integer without a cast"
You are wrong argument to strcmp and strcpy. Signature of strcmp and strcpy are
int strcmp(char *string1, char *string2);
char *strcpy(char *dest, const char *src)
But you are passing it the arguments of char type. Removefrom(s+i)and*(s+j)`. It should be
if (strcmp((s+i), (s+j))==1)
{
strcpy(aux, (s+i));
strcpy((s+i), (s+j));
strcpy((s+j), (s+i));
}
Another problem is you have not allocated memory for the pointer s. For characters, you can declare it as
s = malloc ( (n + 1)*sizeof(char) );
or simply
s = malloc ( n + 1 ); // +1 is for string terminator '\0'
You seem to have mis-understood the return value of strcmp(); it's an integer that will be 0 (zero) if and only if the two string arguments are equal. You're testing for 1, which it will only be rarely; it has no specific meaning.
Consider just using qsort().
You're allocating space for n strings of 1 byte each. The easiest approach is to assume each string will be less than some set length, like 40 bytes. Then you would allocate the memory like this:
s=(char*)calloc(n*(40),sizeof(char));
Then your scanf needs to be modified:
scanf("%s",s+(i*40));
Now, string 1 will be at *s, string 2 will be at *(s+40), etc. Keep in mind that a string ends with a null character (0x00), so the string can only contain 39 chars. Any unused data will also be 0x00.
Do the same s+(i*40) for the sorting algorithm, compare to >0, not ==1, and strcmp, strcpy expect pointers. Then you should be good.
In your code there are a lots of mistakes: in variable declarations, memory allocation and pointer usage.
First remember that you should always reserve enough space to store your string values, and be aware to don't try to store a string with a length greater then the reserved space.
Also you should be very careful managing pointers (s+1 doesn't point to the first string but to the second one, s+n points out of the allocated memory)
So, as mentioned in other answers you should decide the maximum size of your strings an then allocate for them the right amount of memory.
Then I suggest you to use a pointer to strings, i.e. a char** to access your strings and manage the sort, in this way the code is more readable and the sort is faster (you don't need to copy strings, but only to switch pointers)
So your main function should be:
int main()
{
int i, n;
// Declare the pointer to the memory where allocate the space for the strings
char* a; // points to a char ( == is a string)
// Declare the pointer to the memory where store the pointer to the strings
char** s; // points to a char* ( == is a pointer to a string)
printf("give the number of strings:\n");
scanf("%d", &n);
// Allocate the memory for n strings of maximum 40 chars + one more for the null terminator
a=(char*)calloc(n*41, sizeof(char));
// Allocate memory for n pointers to a string
s=(char**)calloc(n, sizeof(char*));
// Notice the 0-based loop
for (i=0; i<n; i++)
{
s[i] = a + i*41; // set the i-th element of s to point the i*41-th char in a
printf("s[%d]= ", i);
scanf("%40s", s[i]); // read at least 40 characters in s[i],
// otherwise it will overflow the allocated size
// and could generate errors or dangerous side effects
}
sort(s,n);
show(s,n);
// Remember always to free the allocated memory
free(s);
free(a);
return 0;
}
the sort function sorts an array of pointers, without copying strings:
void sort (char** s, int n)
{
int i, j;
char* aux;
// Notice the 0-based loop
for (i=0; i<n; i++)
{
for (j=i+1; j<n; j++) //if s[i]> s[j] switch
{
if (strcmp(s[i], s[j])>0)
{
// You don't need to copy strings because you simply copy pointers
aux = s[i];
s[i] = s[j];
s[j] = aux;
}
}
}
}
finally the correct show function:
void show(char** s, int n)
{
int i;
// Notice the 0-based loop
for (i=0; i<n; i++)
{
printf("%s", s[i]);
}
}
I can't test the code but it should works
Added other options
1) If you have troubles with dynamic memory allocation you can use instead static allocation, your main function then will be:
int main()
{
int i, n;
// Declare an array of fixed lenght strings
char s[100][41]; // You manage max 100 strings
printf("give the number of strings:\n");
scanf("%d", &n);
// Ensure that n is less or equal maximum
if (n>100)
{
printf("you'll be asked for a maximum of 100 strings\n");
n=100;
}
// Notice the 0-based loop
for (i=0; i<n; i++)
{
printf("s[%d]= ", i);
scanf("%40s", s[i]); // read at least 40 characters in s[i],
// otherwise it will overflow the allocated size
// and could generate errors or dangerous side effects
}
sort(s,n);
show(s,n);
// You don't need to free any memory
return 0;
}
all other functions remain unchanged.
2) Whereas, if you want the maximum freedom in the memory you need you can choose a two allocate memory separately for each string only for the needed size, in this case your main funcion will be:
int main()
{
int i, n;
char buffer[1000]; // You need a buffer to read input, before known its actual size
// Declare the pointer to the memory where store the pointer to the strings
char** s; // points to a char* ( == is a pointer to a string)
printf("give the number of strings:\n");
scanf("%d", &n);
// Allocate memory for n pointers to a string
s=(char**)calloc(n, sizeof(char*));
// Notice the 0-based loop
for (i=0; i<n; i++)
{
printf("s[%d]= ", i);
scanf("%999s", buffer); // read at least 999 characters in buffer,
// otherwise it will overflow the allocated size
// and could generate errors or dangerous side effects
// Allocate only the memory you need to store the actual size of the string
s[i] = (char*)calloc(strlen(buffer)+1, sizeof(char)); // Remember always 1 more char for the null terminator
// Copy the buffer into the newly allocated string
strcpy(s[i], buffer);
}
sort(s,n);
show(s,n);
// Remember always to free the allocated memory
// Now you have first to free the memory allocated for each string
for (i=0; i<n; i++)
{
free(s[i]);
}
// Then you can free the memory allocated for the array of strings
free(s);
return 0;
}
all other functions remains unchanged too.
Related
#include <stdio.h>
#include <stdlib.h>
char *ptr;
int n;
int main()
{
ptr = (char *)calloc(n, sizeof(char));
// First ID
printf("Enter the length of your employ ID\n");
scanf("%d", &n);
for (int i = 0; i <= n; i++)
{
scanf("%c", &ptr[i]);
}
for (int i = 0; i <= n; i++)
{
printf("%c", ptr[i]);
}
// Second ID
printf("Enter the size of new ID\n");
scanf("%d", &n);
ptr = (char *)realloc(ptr, n * sizeof(char));
for (int i = 0; i <= n; i++)
{
scanf("%c", &ptr[i]);
}
for (int i = 0; i <= n; i++)
{
printf("%c", ptr[i]);
}
// Third ID
printf("Enter the size of new ID\n");
scanf("%d", &n);
ptr = (char *)realloc(ptr, n * sizeof(char));
for (int i =0; i <=n; i++)
{
scanf("%c", &ptr[i]);
}
for (int i = 0; i <= n; i++)
{
printf("%c", ptr[i]);
}
return 0;
}
I tried to Get Ids of three people but the program doesnt work and after taking the input once it just exits : ( . It works fine when I use realloc once but not twice can someone explain why ?
it takes the input and then exits
The statement:
int n;
declares n at file scope. Objects declared at file scope have static storage duration and are always initialised. In the absence of an explicit initialization, they are implicitly initialised to zero.
From the C standard C11 6.7.9/10:
"... If an object that has static or thread storage duration is not
initialized explicitly, then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or
unsigned) zero;"
Accessing out of bounds memory:
Then:
ptr = (char *)calloc(n, sizeof(char));
allocates memory for 0 objects.
The calloc() function allocates memory for an array of nmemb elements
of size bytes each and returns a pointer to the allocated memory. The
memory is set to zero. If nmemb or size is 0, then calloc() returns
either NULL, or a unique pointer value that can later be successfully
passed to free().
On error, these functions return NULL. NULL may also be returned by a
successful call to malloc() with a size of zero, or by a successful
call to calloc() with nmemb or size equal to zero.
But you didn't check the return value of calloc.
Then, this statement:
scanf("%c", &ptr[i]);
tries to access memory that wasn't allocated, and thus invokes undefined Behaviour.
Off by one error:
You have allocated space for n elements, but the condition:
i <= n
tries to access n + 1 elements, which is memory out of bounds, memory you haven't allocated, memory that doesn't belong to you, and is thus undefined behaviour. (But that's irrelevant since you didn't allocate anything in the first place).
Regarding realloc:
The realloc() function returns a pointer to the newly allocated
memory, which is suitably aligned for any kind of variable and may be
different from ptr, or NULL if the request fails. If size was equal to
0, either NULL or a pointer suitable to be passed to free() is
returned. If realloc() fails the original block is left untouched; it
is not freed or moved.
Which means that if it fails and returns NULL, then ptr gets initialised with NULL and you lose all access to the original memory.
One solution is to use another pointer:
char *new = realloc(ptr, size);
if (!new) { /* if realloc failed */
/* deal with it however you wish */
}
/* If we got here, it means that we weren't bounded */
ptr = new;. /* Now ptr points to the new memory, if it didn't already */
new = 0; /* This avoids a dangling pointer */
/* some code relevant to ptr here */
free(ptr); /* For every allocation, there must be a call to free */
Side note: You shouldn't cast the result of malloc and family. It's redundant and may hide a bug. The void * returned by these functions is automatically promoted to the correct type.
Trailing newline:
scanf("%d", &n);
leaves a newline in the input buffer, which automatically gets read by subsequent calls to scanf, and you might never be prompted for input.
Instead of:
scanf("%c");
Use " %c" with a leading blank to skip optional white space:
scanf(" %c");
First of all, please note that you're using:
ptr = (char *)calloc(n, sizeof(char));
when n isn't explicitly initialized in file scope so it is automatically initialized to 0. So basically you overwrite a buffer of size 0 in:
for (int i = 0; i <= n; i++)
{
scanf("%c", &ptr[i]);
}
while exceeding the size allocated with i <= n which sould be i < n, that is probably why.
Second, you must free your memory allocation at the end using free and check allocation's success.
Third, when using strings, you might want to use scanf using %s, unless you have a specific reason.
A more clear and less error prone implementation may be:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int size, times, i;
char *ptr;
printf("Enter the number of IDs to enter\n");
scanf("%d", ×);
for (i = 0; i < times; ++i) {
printf("Enter the size of new ID\n");
scanf("%d", &size);
if (size < 0) {
printf("Entered value is negative\n");
return size; // or any other error
}
// note the '+ 1' so we have a NULL terminating string
ptr = (char *)calloc(size + 1, sizeof(char));
if (ptr == NULL) {
printf("Error allocating ptr\n");
return -1; // or any other error
}
printf("Enter your ID\n");
scanf("%s", ptr);
printf("Your ID is: %s\n", ptr);
free(ptr);
}
return 0;
}
Hopefully I answered everything and didn't miss a thing (:
I need to write a C function that gets from the user the number of the words that he wants to enter, then the function has to scan the word from the user and but them in the array.
For example:
Program:
number of words:
User:
3
hi
my
name
(between every word there is enter) then the function has to put these words in
string array (the size of the array must be defined by malloc and the max size of the string is 100 (could be less)).
int main()
{
int n;
printf("Please enter the number of words: \n");
if (scanf("%d",&n)!=1)
return 0;
char *name;
name = malloc((sizeof(char)*100*n));
int c;
int i;
int m;
for (i = 0; i < n && ((c=getchar()) != EOF );i++)
{
name[i] = c;
}
finds_themin(&name, m); //I know this work
return 0;
}
You need to setup a pointer to pointer.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
char **s;
int n;
char buffer[64];
fgets(buffer,64,stdin);
n=strtol(buffer,NULL,10);// I avoid using scanf
s=(char **)malloc(sizeof(char*)*n);// you need to declare a pointer to pointer
/*
'PtP s' would look like this:
s[0]=a char pointer so this will point to an individual string
s[1]=a char pointer so this will point to an individual string
s[2]=a char pointer so this will point to an individual string
....
so you need to allocate memory for each pointer within s.
*/
int i;
for(i=0;i<n;i++){
s[i]=(char*)malloc(sizeof(char)*100);// length of each string is 100 in this case
}
for(i=0;i<n;i++){
fgets(s[i],100,stdin);
if(strlen(s[i])>=1){// to avoid undefined behavior in case of null byte input
if(s[i][strlen(s[i])-1]=='\n'){ // fgets also puts that newline character if the string is smaller than from max length,
s[i][strlen(s[i])-1]='\0'; // just removing that newline feed from each string
}
else{
while((getchar())!='\n'); //if the string in the command line was more than 100 chars you need to remove the remaining chars for next fgets
}
}
}
for(i=0;i<n;i++){
printf("\n%s",s[i]);
}
for(i=0;i<n;i++){
free(s[i]); //avoiding leaks
}
free(s);
}
As you need to store an array of strings you need an array of char* or char** to point each string (char array).
char **name;
name = malloc(n); // to store n strings.
Then in the loop use fgets to read the input as a line. Also, you need to allocate the memory for each new char array.
fflush(stdin);
for (i = 0; i < n; i++) {
name[i] = malloc(100); // allocating memory for string.
fgets (name[i], 100, stdin); // 100 is the max len
}
You can then simply iterate over the char** array, the ith index will point to the ith string.
for (i = 0; i < n; i++) {
// printf("%s", name[i]);
}
So basically, right now, this function can only take 9 words with 10 characters each. How do i make it so that it can take an arbitrary amount of words and characters and sort them accordingly in alphabetical order?
int sortText(){
char name[10][9], tname[10][9], temp[10];
int i, j, n;
printf("Enter the amount of words you want to sort (max 9):");
scanf("%d", &n);
printf("Enter %d words: ",n);
for (i = 0; i < n; i++)
{
scanf("%s", name[i]);
strcpy(tname[i], name[i]);
}
for (i = 0; i < n - 1 ; i++){
for (j = i + 1; j < n; j++){
if (strcmp(name[i], name[j]) > 0){
strcpy(temp, name[i]);
strcpy(name[i], name[j]);
strcpy(name[j], temp);
}
}
}
printf("\n------------------------------------------\n");
printf("%-3s %4s %11s\n", "Input","|", "Output");
printf("------------------------------------------\n");
for (i = 0; i < n; i++)
{
printf("%s\t\t%s\n", tname[i], name[i]);
}
printf("------------------------------------------\n");
}
You have two problems, that each needs to be solved separately, but they can still be solved in a similar way, namely using dynamic memory allocations and more importantly reallocation.
There are two important aspects to remember here, and the first is that a string is an array of characters (with a special terminating character) and that you can have a pointer to an array located anywhere in memory.
If we start with the data-types and how you should store your strings, what you want is an array of arrays, much like you have right now, but allocated dynamically which means you want an array of pointers (to the strings), but since the array of string also needs to be dynamic you need a pointer to an array which contains pointers to other arrays, i.e. a pointer to a pointer to char: char **.
Now when we know what data-type to use, lets think about how to allocate it. To allocate space for a single string in your array, you allocate one char * using the malloc function:
char **strings = malloc(1 * sizeof(char *));
That was the simple part. Now before we start reading the actual string, lets think about how to add a new string to your collection: This is done by reallocating the array of strings you have, using the realloc function:
char **temp_strings = realloc(strings, current_count + 1 * sizeof(char *));
if (temp_string == NULL)
{
// Allocation failed, handle error appropriately
}
strings = temp_strings;
++current_count;
Here the variable current_count is the current length of the array of strings, it should be initially initialized to 1 (as we only have a single string in the array).
Now for the reading of the actual strings, and this is a little more complicated since we actually can't read whole strings (since we don't know how long each line is). Instead we read one character at a time, and end when we hit a newline. We also need to reallocate the string for each character.
Maybe something like this:
int ch;
char *s = NULL;
size_t current_length = 0; // Current length of string
while ((c = fgetc(stdin)) != EOF)
{
if (c == '\n')
break; // Newline, done with the current string
if (s == NULL)
{
s = malloc(2); // Allocate two character: One for c and one for the terminator
}
else
{
// The current length is not including the terminator
// that's why we add two characters
char *temp_s = realloc(s, current_length + 2);
if (temp_s == NULL)
{
// Handle error
}
s = temp_s;
}
s[current_length++] = c;
s[current_length] = '\0'; // Terminate as a string
}
if (s != NULL)
{
// "Add" the string to the array of strings
strings[current_count] = s;
}
For C only you should use char pointer located dynamic.
You can make list by implement a linked list. Then strcmp still work well.
See about linked list here:
http://www.cprogramming.com/tutorial/c/lesson15.html
If i want to take an input in a 2d array with each string in one row, and the next in the other(i.e. change the row on pressing enter). How can i do that in C. C doesnt seem to have convenient "String" Handling. I obviously mean doing so without the use of getchar().
3 ways are there which are mentioned below.
If you know the maximum number of strings and maximum number of chars, then you can use the below way to declare a 2D character array.
char strs[MAX_NO_OF_STRS][MAX_NO_CHARS] = {0};
for (i = 0; i < MAX_NO_OF_STRS; i++)
{
scanf("%s", strs[i]);
}
If you know the maximum number of strings, and you dont want to waste the memory by allocating memory for MAX_NO_CHARS for all strings. then go for array of char pointers.
char temp[MAX_NO_CHARS] = {0};
char *strs[MAX_NO_OF_STRS] = NULL;
for (i = 0; i < MAX_NO_OF_STRS; i++)
{
scanf("%s", temp);
strs[i] = strdup(temp);
}
If you know the maximum number of strings during run time means, you can declare a double pointer of char. Get the number of strings n from user and then allocate memory dynamically.
char temp[MAX_NO_CHARS] = {0};
char **strs = NULL;
int n = 0;
scanf("%d", &n);
strs = malloc(sizeof(char*) * n);
for (i = 0; i < n; i++)
{
scanf("%s", temp);
strs[i] = strdup(temp);
}
#include<stdio.h>
main()
{
char student_name[5][25];
int i;
for(i=0;i<5;i++)
{
printf("\nEnter a string %d: ",i+1);
scanf(" %[^\n]",student_name[i]);
}
}
u can read strings using 2d array without using getchar() by putting space in scanf(" %[^\n]")
; before %[^\n]!
An alternative to using malloc and filling up an array of pointers with buffers of a fixed size, would be to allocate a 2d array (in static storage or on the stack) and fill it up. KingsIndian modifed code example would than look like this:
#include <stdio.h>
int main()
{
char str[2][256] = {{0}};
int i = 0;
for(i=0;i<2;i++)
{
scanf("%255s", &str[i][0]);
}
return 0;
}
If all strings you expect to get are no longer than some size, than this approach will spare you the need to deal with freeing the memory yourself. It is less flexible however, meaning that you can't fit the size of an individual buffer to the string it contains.
EDIT
Adding to the information in the comment, to read a string that is terminated only by a new-line, rather than by any whitespace:
scanf("%255[^\n]", str[i]);
i tried to take input from user
input type is not determined(can be char or int)
i wanna take input and store in pointer array
while i doing that job forr each pointer i wanna take place from leap area
that is using malloc
but below code doesnot work why???
int main(void)
{
char *tutar[100][20],temp;
int i;
int n;
i=0;
while(temp!='x')
{
scanf("%c",&temp);
tutar[i]=malloc(sizeof(int));
tutar[i]=temp;
++i;
}
n =i;
for(i=0;i<=n;++i)
{
printf(" %c ",*tutar[i]);
}
printf("\n\n");
/*for(i=0;i<=n;++i)
{
printf("%d",atoi(*tutar[i]));
}
*/
}
note that;
this cite has problem when rewrite(edit) the previous mail
it is general problem or not
There are several problems in your code, including:
you declare tutar as a two-dimensional array of pointers to character, then use it as a one-dimensional array
tutar[i]=temp assigns the value of temp (a char) to tutar[i] (a pointer to char), effectively overwriting the pointer to the newly reserved memory block
you don't initialize temp, so it will have garbage value - occasionally it may have the value x, in which your loop will not execute
Here is an improved version (it is not tested, and I don't claim it to be perfect):
int main(void)
{
char *tutar[100], temp = 0;
int i = 0;
int n;
while(temp!='x')
{
scanf("%c",&temp);
tutar[i]=malloc(sizeof(char));
*tutar[i]=temp;
++i;
}
n =i;
for(i=0;i<=n;++i)
{
printf(" %c ",*tutar[i]);
}
printf("\n\n");
}
Note that unless you really need to allocate memory dynamically, you would be better off using a simple array of chars:
char tutar[100], ...
...
while(temp!='x')
{
scanf("%c",&temp);
tutar[i++]=temp;
}
...
For the sake of brevity, I incremented i within the assignment statement.