Reading array of string in C - c

I need to read an array of n strings from 2 letters in each (e.g. n = 3, need to read something near "ab bf cs"). I use this code and get segmentation fault:
int n;
scanf("%d", &n);
char array[n][2];
char *tmp;
for (int i = 0; i < n; i++)
{
scanf("%s", &tmp);
strcpy(array[i], tmp);
}
Please help me to fix it!

Problem 1
To store a string of length 2, you need a char array of size 3. Use:
char array[n][3];
Problem 2
You are using &tmp in the call to scanf. That is wrong on two accounts.
The type is not appropriate. Type of &tmp is char**. scanf needs a char* with the %s format specifier.
&tmp cannot hold a string.
You could use
scanf("%s", tmp);
That will be OK from type point of view but it won't ok from run time point of view since tmp does not point to anything valid.
You can do away with tmp altogether and use:
scanf("%s", array[i]);
That entire block of code can be:
int n;
scanf("%d", &n);
char array[n][3];
for (int i = 0; i < n; i++)
{
// Make sure you don't read more than 2 chars.
scanf("%2s", array[i]);
}

There are a couple things you need to fix here.
Remember that one "string" (char[]) always ends with a null terminating character \0. So, whenever you create a char[], you must leave enough space for that. For example:
char str[3] = "foo"; looks like ['f', 'o', 'o'], but
char str[4] = "foo"; looks like ['f', 'o', 'o', '\0'].
Unexpected consequences can occur when using the former.
This means that you should change char array[n][2] to char array[n][3].
Remember that pointers are different than arrays. If you want to use a pointer, you must allocate memory for it, otherwise you will most likely seg fault.
In your program, it's simple enough that you can probably get away with not using a pointer, especially since you know the the length of each string that you will be storing (2).
You could change char *tmp to char tmp[3].
You can actually refactor your code so you don't need the tmp variable at all. If you want, you can just store the word you read into the array directly. For example:
scanf("%s", array[n]);
If you are really insistent on using that tmp variable as a char *, then allocate memory for it, like so:
char *tmp = (char*)malloc(3 * sizeof(char));
As a sidenote, if you are adhering to the ISO C90 standards, you shouldn't intermix variable declarations in code, so in your loop where you have for(int i = 0...), you should declare int i; at the top of the file, and then assign it in the loop for(i = 0...).

First, as user3121023 pointed out in the comments, char *tmp; creates a pointer without memory allocated to it. scanf() needs an array, and you need space for the terminating '\0' (which is probably the source of your segmentation fault). So you could try scanf("%s", array[i]);.
Second, it's a good idea to use "%2s" instead of "%s" so the user doesn't input 3 digits and overflow your buffer.
Here's one solution.
int n;
scanf("%d", &n);
char array[n][3];
for (int i = 0; i < n; i++)
{
scanf("%2s", array[i]);
}

Related

random chars in dynamic char array C

I need help with char array. I want to create a n-lenght array and initialize its values, but after malloc() function the array is longer then n*sizeof(char), and the content of array isnt only chars which I assign... In array is few random chars and I dont know how to solve that... I need that part of code for one project for exam in school, and I have to finish by Sunday... Please help :P
#include<stdlib.h>
#include<stdio.h>
int main(){
char *text;
int n = 10;
int i;
if((text = (char*) malloc((n)*sizeof(char))) == NULL){
fprintf(stderr, "allocation error");
}
for(i = 0; i < n; i++){
//text[i] = 'A';
strcat(text,"A");
}
int test = strlen(text);
printf("\n%d\n", test);
puts(text);
free(text);
return 0;
}
Well before using strcat make
text[0]=0;
strcat expects null terminated char array for the first argument also.
From standard 7.24.3.1
#include <string.h>
char *strcat(char * restrict s1,
const char * restrict s2);
The strcat function appends a copy of the string pointed to by s2
(including the terminating null character) to the end of the string
pointed to by s1. The initial character of s2 overwrites the null
character at the end of s1.
How do you think strcat will know where the first string ends if you don't
put a \0 in s1.
Also don't forget to allocate an extra byte for the \0 character. Otherwise you are writing past what you have allocated for. This is again undefined behavior.
And earlier you had undefined behavior.
Note:
You should check the return value of malloc to know whether the malloc invocation was successful or not.
Casting the return value of malloc is not needed. Conversion from void* to relevant pointer is done implicitly in this case.
strlen returns size_t not int. printf("%zu",strlen(text))
To start with, you're way of using malloc in
text = (char*) malloc((n)*sizeof(char)
is not ideal. You can change that to
text = malloc(n * sizeof *text); // Don't cast and using *text is straighforward and easy.
So the statement could be
if(NULL == (text = (char*) malloc((n)*sizeof(char))){
fprintf(stderr, "allocation error");
}
But the actual problem lies in
for(i = 0; i < n; i++){
//text[i] = 'A';
strcat(text,"A");
}
The strcat documentation says
dest − This is pointer to the destination array, which should contain
a C string, and should be large enough to contain the concatenated
resulting string.
Just to point out that the above method is flawed, you just need to consider that the C string "A" actually contains two characters in it, A and the terminating \0(the null character). In this case, when i is n-2, you have out of bounds access or buffer overrun1. If you wanted to fill the entire text array with A, you could have done
for(i = 0; i < n; i++){
// Note for n length, you can store n-1 chars plus terminating null
text[i]=(n-2)==i?'A':'\0'; // n-2 because, the count starts from zero
}
//Then print the null terminated string
printf("Filled string : %s\n",text); // You're all good :-)
Note: Use a tool like valgrind to find memory leaks & out of bound memory accesses.

pointer being assigned values with a loop

I am trying to make an array with 10 pointers which will receive the input from scanf within a for loop. Then I want to call that list. However, I get a runtime error for memory:
#include <stdio.h>
int main(void) {
int i;
char * string[10];
//printf("%s", *string[0]);
for(i = 0; i<3; i++)
{
printf("what is string");
scanf("%s", string[i]);
printf("%s", string[i]);
}
return 0;
}
You need to think about the data structure with which you are attempting to store your strings.
char * string[10];
This declares an array of 10 elements of type "char *" or "pointer to a char".
Now think about what you are doing with this operation.
scanf("%s", string[i]);
You are using scanf to attempt to read user input. Does your function call make sense though?
The first parameter is your format string. "%s" makes sense because you want the user to provide you a string. Let's ignore the fact that you have not put any bounds on the length of that input for the moment.
Your second parameter needs to be be the variable where you want to store the input. You have provided "string[i]". Remember that in C, strings are just char arrays. However, your variable "string[i]" has the type "char *". This doesn't make sense. How can you store data of type "char array[]" in variable of type "char * array[]"? The types are different.
You need to create a buffer within which you can store your input string. Something like:
char buffer[256];
Then you call scanf like:
scanf("%s", buffer);
Keep in mind that this isn't the best idea because you don't know how many characters the user might enter. This will take the input character array and store them in a variable that correctly represents that data.
Note that this call would be safer:
fgets(buffer, sizeof(buffer)/sizeof(char), stdin);
fgets will read a fixed number of characters from the stream. In the above call I define that number by just taking the length of my buffer variable. I divide by sizeof(char) just to make sure that any strange representation issues where a char != 1 byte are taken care of. Also note that you will end up with the carraige return in your buffer (fgets will grab it).
Once you have your string in an appropriate variable, you can save it and get a pointer to a copy of that string with:
char * ptr = strdup(buffer);
This will create a new copy of the string stored in buffer and return a pointer to that new copy location. This pointer can then go into your array.
Note that you cannot just do:
string[i] = buffer
Because string[i] is just a pointer to the buffer variable...which will be overwritten during each iteration! You would end up with an array of pointers to the same variable, which would all end up giving you to the same string (the last input).
Put it all together in something like this:
char buffer[256];
printf("What is your string? ");
fgets(buffer, sizeof(buffer)/sizeof(char), stdin);
string[i] = strdup(buffer);
Because strdup() uses a malloc under the hood, you will need to free all your strings at the end of your program with:
int i = 0;
for(; i < sizeof(string)/sizeof(char *); i++) {
if(string[i]) free(string[i]);
}
You need to either allocate memeory dynamically or make your 2-d array:
char string[10][100];
You can do something like this to allocate memory -
for(i=0;i<10;i++){
string[i]=malloc(sizeof(char)*10);
}
So that your program does not give error.
But after this you have to free the memory allocated.

Create an Array of Strings from an Array of Ints in C

I'm attempting to convert an array of ints to an array of strings in c. My code so far is:
int args[] = {1, 3000};
char *str_args[15];
int i = 0;
for(i; i<=((sizeof(args)/sizeof(args[0]))); i++){
char buffer[10];
sprintf(buffer, "%d", args[i]);
str_args[i] = buffer;
}
printf("%s\n", *str_args[0]);
This code causes my program to crash instead of outputting 1 (the first arg) like I expect. What am I missing here? Thanks in advance
It's because you assign each entry of str_args to a local pointer, one that goes out of scope once the loop loops.
You might want to consider strdup:
str_args[i] = strdup(buffer);
Of course, you then have to free the memory allocated by strdup.
You also have a problem when printing just after the loop, when you want to print a string, but *str_args[0] dereferences the first string. i.e. it's the first character and not a string. Remove the dereferencing operator * and it should work just fine.
On the printf, the datatype of the parameter is incorrect
Also you need to copy temporary "buffer" to allocated memory or each loop overwrites the next
Code below fixes these two problems
#include<stdio.h>
#include<string.h>
main() {
int args[] = {1, 3000};
char *str_args[15];
int i = 0;
for(i; i<=((sizeof(args)/sizeof(args[0]))); i++){
char buffer[10];
sprintf(buffer, "%d", args[i]);
str_args[i] = strdup(buffer);
}
printf("%s\n", str_args[0]);
}
for(i; i<=((sizeof(args)/sizeof(args[0]))); i++){
should be :
for(i=0; i<((sizeof(args)/sizeof(args[0]))); i++){//take out the `=` after >, add i=0 first.
As the way it is originally written, i will reach 2, and cause the overrun you experienced.
(i=0 is optional since you have i initialized in the line before, but its better form to just do it in the for loop.)
You are overrunning your buffers otherwise. BTW, you do realize that there are only two items in the following array, right?
int args[] = {1, 3000};

Using scanf with array of pointers

char* username[30];
memset(username,0x00,30);
scanf("%s",&username);
would this make pointers point to random place in memory or it's safe to use ?
char *username[30] is an array of pointers, not characters. So your code is very wrong (as in not safe). To get an array of characters you need:
char username[30];
char* username[30]; //is array of char pointers.
//Allocate memory for these pointers using calloc(). so no need of memset().
memset(username,0x00,30);//can be removed.
scanf("%s",&username);//It should be scanf("%s",username[i]);
#perreal, Sample added.
#define SIZE 100 //100 chars...
char* username[30];
int i;
for(i = 0; i < 30; i++)
{
username[i] = calloc(SIZE, sizeof(char)); //Add Fail checks if needed.
scanf("%s",username[i]);
}
so with the above code, you can get 30 strings. If you need only one string with 30 char then
char username[30];
memset(username,0x00,30);
scanf("%s",username);
is enough.
with
memset(username,0x00,30);
you are initializing the first 30 bytes of your array of pointers and not the whole array
memset(username,0, sizeof(username));
would set everything to 0 although a simple loop is clearer for the reader (IMHO)
for (int i = 0; i < 30; username[i++] = NULL) {;}
don't do this:
scanf("%s",&username);
scanf doesn't magically allocate anything -- "username" is an array of pointers and are NULL pointers, how should scanf know how to allocate memory etc? Instead do a loop, let user enter a string, allocate memory for that string (+1), copy the string to the allocated memory and assign it to "username[i]".
What you PROBABLY want is:
int i;
char* username[30];
for(i = 0; i < 30; i++)
{
username[i] = calloc(100, sizeof(char)); // or whatever size your string is.
scanf("%s",username[i]);
}
... Code using usernames ...
for(i = 0; i < 30; i++)
{
free(username[i]);
}
But personally, I'd probably go for:
int i;
char username[30][100];
for(i = 0; i < 30; i++)
{
scanf("%s",username[i]);
}
Saves on having to free the pointers later.
That will read 30 strings into your username array.
If you want to just read one username:
char username[30] = {0}; // Same as memset, but shorter to write!
scanf("%s", username);
Although as others have suggested, scanf() is't the best function to read "user generated input" - it's fine for data that your program has already "checked" (that is, it contains no "funny stuff", fits in the length provided, etc) and written to a file [using fscanf()]. For user input, use fgets() to read a line of text, and then work through it in whatever way is suitable to get the actual data out of the string.
For example, if some username has more than 100 characters [or thirty in the last example], the string will overflow, and nothing good will ever come from that [and in really bad cases, you won't notice until MUCH later, which makes it hard to debug - if you are lucky, it crashes immediately].
char* username[30];
memset(username,0x00,30);
scanf("%s",&username);
the above your code will get crash , because you are trying to input into pointer for which memory is not allocated. so first you allocate memory for the pointers and then you read into that memory location.
char *username[30]
This is an array of pointers to characters..
go for char username[30]

Sorting an array of strings in C

I have an assignment I've been working on for a few hours now, and I can't seem to get it quite right. The assignment is to take a random number of names (from stdin), sort them, and then output them in alphabetical order. I can't find any sites online that handle this kind of sorting specifically, and have had no luck trying to implement qsort() into my code.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int stringcmp(const void *a, const void *b)
{
const char **ia = (const char **)a;
const char **ib = (const char **)b;
return strcmp(*ia, *ib);
}
void main(int argc, char *argv[])
{
char *input[] = {" "};
char temp[20][20];
int i = 0;
int num = 0;
int place = 0;
int stringlen = sizeof(temp) / sizeof(char);
printf("How many names would you like to enter? ");
scanf("%d", &num);
while (place < num)
{
printf("Please input a name(first only): ");
scanf("%s", input[place]);
printf("The name you entered is: ");
printf("%s\n", input[place]);
place++;
}
//qsort(temp, stringlen, sizeof(char *), stringcmp); <-- just an idea I was messing with
qsort(input, stringlen, sizeof(char *), stringcmp);
printf("Names:\n");
for(i=0; i<place; i++)
printf("%s\n", input[i]);
system("PAUSE");
return(EXIT_SUCCESS);
}
The main problem is, when I go to output my code, I cannot use the char *input variable because of how its declared. The temp[] will display, but will not be sorted by qsort because it is not declared as a pointer. Any ideas?
You can't declare your input array like that. Since you know how many the user requires, you can dynamically allocate the array:
char **input = malloc(num * sizeof(char*));
Likewise, when you read your strings in, they need somewhere to go. Simply passing an uninitialized pointer to scanf is not okay. I suggest you define the maximum length of a name and have a temporary buffer for reading it:
const size_t MAX_NAME = 50;
char name[MAX_NAME];
...
for( i = 0; i < num; i++ )
{
printf("Please input a name(first only): ");
scanf("%s", name);
input[i] = strdup(name);
}
[Note this does not prevent the user from overflowing the 'name' buffer. I used scanf for illustrative purposes only]
You seem to be passing the wrong array length to qsort. Try this:
qsort(input, num, sizeof(char *), stringcmp);
When you are finished, you need to release memory for all the names and the array.
for( i = 0; i < num; i++ ) free(input[i]);
free(input);
could you explain
the ** declarations throughout the code? I'm not sure what they're
used for, although I know the function for stringcmp is a widely used
algorithm, I have no idea how it works; I'm thrown off by the double
de-reference markers.
Yep, in the case where I used it, I am telling C that to get a single character, I have to dereference a pointer twice. When you index a pointer, it's dereferencing. So I allocated an array by requesting a block of memory containing num * sizeof(char*) bytes. Because I assigned that pointer to a char**, the compiler knows that I am pointing to a chunk of memory that contains char* values.
If I ask for input[0] (this is the same as *input) it should look at the very start of that memory and pull out enough bytes to form a char*. When I ask for input[1], it skips past those bytes and pulls out the next bunch of bytes that form a char*. Etc... Likewise, when I index a char*, I am pulling out single characters.
In your stringcmp function, you have the following situation. You passed a void* pointer to qsort so it doesn't actually know the size of the data values stored in your array. That's why you have to pass both the array length AND the size of a single element. So qsort just blindly rips through this arbitrary-length array of arbitrary-sized values and fires off memory addresses that ought to contain your data for comparison. Because qsort doesn't know anything else about your array elements except where they are located, it just uses void*.
But YOU know that those pointers are going to be the memory addresses of two of your array elements, and that your array elements are char*. So you need the address of a char* (hence you cast the pointers to char**). Now you need to dereference these pointers when you call strcmp() because that function requires a char* (ie a value that points directly to the memory containing your string characters). That is why you use the * in strcmp(*ia, *ib).
One quick way to fix your program is to declare input as an array of pointers, like this:
char *input[20];
When you read names in, use tmp[place] for your buffer, and store the pointer into input, like this:
scanf("%19s", tmp[place]);
input[place] = tmp[place];
Now sorting the input should work fine.
This has a limitation of being limited to 20 lines of 20 characters max. If you learned about malloc in the class, you should be able to fix that by allocating your strings and the string array dynamically.

Resources