I'm new at C and I'm trying to do an exercise which asks to insert some strings and then store them. First it requests a multidimensional array where we have for every row of the array a string, and then as an array of pointers.
Here's the code for the first part. I don't know how to store into an array some strings that are not already written.
For the second one I have no idea since I've never done exercises with pointers before.
#include <stdio.h>
int main(){
int n; //number of strings
int x; //number of characters per string
printf("How many strings do you want to insert?");
scanf("%d", &n);
if ((n >= 1) && (n <= 20)){
printf("How many characters per string?");
scanf("%d", &x);
char str[x];
if (x <= 10){
for(int i = 0; i < n; i++){
printf("Insert a string:");
scanf("%s", str);
for(int j = 0; j < x; j++){
char arr[j];
arr[j] = str[x];
printf("%s", arr);
}
}
}
else {
printf("Error:the number of characters must be < 10");
}
}
else {
printf("Error: the number must be < 20");
}
return 0;
}
... requests a multidimensional array where we have for every row of the array a string, and then as an array of pointers.
After getting the qualified number of strings, allocate an array of pointers to char.
if ((n >= 1) && (n <= 20)){
char **string_list = calloc(n, sizeof *string_list);
assert(string_list); // or other error checking
(Notice no type in = calloc(n, sizeof *string_list);. Easier to code right, review and maintain.)
Read the strings in a working temp buffer. As "How many characters per string?" likely means the number of characters not including the null character, our str[] needs a +1 in size.
// char str[x]; // too small
char str[x+1];
Yet we know x <= 10 and can use a fixed buffer size and limit input length
for(int i = 0; i < n; i++){
char str[10+1];
printf("Insert a string:");
scanf("%10s", str); // Notice the 10 - a width limit
// TBD check if scanf() returned 1 and if str is longer than x
Now allocate a copy of the str
string_list[j] = strdup(str);
assert(string_list[j]); // or other error checking
}
Later, when done with string_list[], clean-up and free allocations.
for (int i=0; i<n; i++) {
free(string_list[i]);
}
free(string_list);
What is weak about this:
It uses scanf() rather than fgets() and then parses, has minimal error checking, does not take in strings with spaces, does not handle over-long input, strdup() is not standard -yet, etc.
So the above is a baby step. Better code would handle the weak issues.
Related
i am new to c programming. The value of the code needs to be 0 after the loop but it changes. Please help someone.
#include<stdio.h>
#include<string.h>
int main(void)
{
int n, i, k, j, sum;
char input[] = "";
scanf("%d", &n);
sum = 0;
for (i = 0; i< n; i++)
{
scanf("%s", &input[i]);
//sum = sum + (input[i]-48);
}
printf("%d", sum);
}
When you declare an array but leave the size blank, it is sized to exactly fit what it is initialized with.
In this case you initialize it with an empty string which is 1 byte long (for the terminating null character) so the array is only 1 character wide. So if you attempt to read any nonempty string into this variable you'll write past the bounds of the array. Doing so invokes undefined behavior.
As a start, make the array at least as large as you expect the input to be, for example:
char input[80];
Then read the string once, limiting the input to the size of the array minus 1, then loop through the values:
scanf("%79s", input);
for (i = 0; i< n; i++)
{
sum = sum + (input[i]-48);
}
I allocated a 2D array of characters, and while reading strings with no whitespaces between, the code is working fine. When I read them with whitespaces, I'm facing a bug. How do I read all N number of Strings, each in a single line, each one containing whitespaces.
Example input:
Enter total number of Strings : 3
Enter all the 3 Strings :
John Doe
Jane Doe
Trad Braversy
My code:
// Code to enter the total number of Strings :
int N;
printf("\n\tEnter the total number of Strings : ");
scanf("%d", &N);
// Code for allocating initial memory to them :
char** strings = (char**)malloc(N * sizeof(char*));
for (int i = 0; i < N; ++i) {
strings[i] = (char*)malloc(1024 * sizeof(char));
}
// Code for entering all the N strings :
printf("\n\tEnter all the %d Strings :\n", N);
for (int i = 0; i < N; ++i) {
gets(strings[i]);
}
// Code to reallocate the memory according to the entered length :
for (int i = 0; i < N; ++i) {
strings[i] = (char*)realloc(strings[i], strlen(strings[i]) + 1);
}
A few observations:
It's safer to read a full line of text, then parse out the integer from that, rather than doing scanf() for a single integer. This is because the latter leaves the newline in the stream, which can confuse later reads.
There's no real point in using malloc() to do dynamic memory allocation for this, you can use a VLA:
char strings[N][1024];
Note that using a capital-only symbol for a runtime variable is stylistically strange in C.
Then, it's much better to use fgets(), it's safer and just better:
for (int i = 0; i < N; ++i)
{
if (fgets(strings[i], sizeof strings[i], stdin) == NULL)
{
fprintf(stderr, "**Read error on string %d\n", i);
exit(1);
}
}
And as always, be prepared that I/O can fail, and try to handle that.
I'm having trouble with trying to manipulate 2d dynamic arrays in C. What I want to do is to store a char string in every row of the the 2d array then perform a check to see if the string contains a certain character, if so remove all occurrences then shift over the empty positions. What's actually happening is I get an exit status 1.
More about the problem, for example if I have
Enter string 1: testing
Enter string 2: apple
Enter string 3: banana
I would want the output to become
What letter? a // ask what character to search for and remove all occurences
testing
pple
bnn
Here is my full code:
#include <stdio.h>
#include <stdlib.h>
void removeOccurences2(char** letters, int strs, int size, char letter){
// Get size of array
// Shift amount says how many of the letter that we have removed so far.
int shiftAmt = 0;
// Shift array says how much we should shift each element at the end
int shiftArray[strs][size];
// The first loop to remove letters and put things the shift amount in the array
int i,j;
for(i=0;i < strs; i++){
for(j = 0; j < size - 1; j++) {
if (letters[i][j] == '\0'){
break;
}
else {
// If the letter matches
if(letter == letters[i][j]){
// Set to null terminator
letters[i][j] = '\0';
// Increase Shift amount
shiftAmt++;
// Set shift amount for this position to be 0
shiftArray[i][j] = 0;
}else{
// Set the shift amount for this letter to be equal to the current shift amount
shiftArray[i][j] = shiftAmt;
}
}
}
}
// Loop back through and shift each index the required amount
for(i = 0; i < strs; i++){
for(j = 0; j < size - 1; j++) {
// If the shift amount for this index is 0 don't do anything
if(shiftArray[i][j] == 0) continue;
// Otherwise swap
letters[i][j - shiftArray[i][j]] = letters[i][j];
letters[i][j] = '\0';
}
//now print the new string
printf("%s", letters[i]);
}
return;
}
int main() {
int strs;
char** array2;
int size;
int cnt;
int c;
char letter;
printf("How many strings do you want to enter?\n");
scanf("%d", &strs);
printf("What is the max size of the strings?\n");
scanf("%d", &size);
array2 = malloc(sizeof(char*)*strs);
cnt = 0;
while (cnt < strs) {
c = 0;
printf("Enter string %d:\n", cnt + 1);
array2[cnt] = malloc(sizeof(char)*size);
scanf("%s", array2[cnt]);
cnt += 1;
}
printf("What letter?\n");
scanf(" %c", &letter);
removeOccurences2(array2,strs,size,letter);
}
Thanks in advance!
You can remove letters from a string in place, because you can only shorten the string.
The code could simply be:
void removeOccurences2(char** letters, int strs, int size, char letter){
int i,j,k;
// loop over the array of strings
for(i=0;i < strs; i++){
// loop per string
for(j = 0, k=0; j < size; j++) {
// stop on the first null character
if (letters[i][j] == '\0'){
letters[i][k] = 0;
break;
}
// If the letter does not match, keep the letter
if(letter != letters[i][j]){
letters[i][k++] = letters[i][j];
}
}
//now print the new string
printf("%s\n", letters[i]);
}
return;
}
But you should free all the allocated arrays before returning to environment, and explicitely return 0 at the end of main.
Well, there are several issues on your program, basically you are getting segmentation fault error because you are accessing invalid memory which isn't allocated by your program. Here are some issues I found:
shiftAmt isn't reset after processing/checking each string which lead to incorrect value of shiftArray.
Values of shiftArray only set as expected for length of string but after that (values from from length of each string to size) are random numbers.
The logic to delete occurrence character is incorrect - you need to shift the whole string after the occurrence character to the left not just manipulating a single character like what you are doing.
1 & 2 cause the segmentation fault error (crash the program) because it causes this line letters[i][j - shiftArray[i][j]] = letters[i][j]; access to unexpected memory. You can take a look at my edited version of your removeOccurences2 method for reference:
int removeOccurences2(char* string, char letter) {
if(!string) return -1;
int i = 0;
while (*(string+i) != '\0') {
if (*(string+i) == letter) {
memmove(string + i, string + i + 1, strlen(string + i + 1));
string[strlen(string) - 1] = '\0'; // delete last character
}
i++;
}
return 0;
}
It's just an example and there is still some flaw in its logics waiting for you to complete. Hint: try the case: "bananaaaa123"
Happy coding!
"...if the string contains a certain character, if so remove all occurrences then shift over the empty positions."
The original string can be edited in place by incrementing two pointers initially containing the same content. The following illustrates.:
void remove_all_chars(char* str, char c)
{
char *pr = str://pointer read
char *pw = str;//pointer write
while(*pr)
{
*pw = *pr++;
pw += (*pw != c);//increment pw only if current position == c
}
*pw = '\0';//terminate to mark last position of modified string
}
This is the cleanest, simplest form I have seen for doing this task. Credit goes to this answer.
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]);