I built this code to practice pointers and the program keeps crashing.it seems it crashes when I enter a big number to counter. 1-5 doesn't affect it apparently, but when you enter 30 it keeps crashing, sometimes on the allocation itself malloc(... and sometime in the free(names[i]); function.
What's the problem here?
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
int main() {
char **names;
char buffer[100];
int i, bufferLen, counter;
printf("how many names? ");
scanf_s("%d", &counter);
if (counter < 0) {
printf("wrong choice\n");
return 1;
}
names = (char**)malloc(77 * sizeof(char));
if (names == NULL) {
printf("failed...\n");
return 1;
}
for (i = 0; i < counter; i++) {
printf("write the name!! (up to 100 chars): \n");
gets_s(buffer, sizeof(char) * 100);
bufferLen = strlen(buffer) + 1;
names[i] = (char*)malloc(sizeof(char)*bufferLen);
if (names[i] == NULL) {
printf("failed...\n");
return 1;
}
strcpy_s(names[i], sizeof(char)*bufferLen, buffer);
}
for (i = counter-1; i >= 0; i--) { //print names
printf("no. %d, ptr no. %d (size: %d bytes): \n", i+1, (int)(names[i]), sizeof(names[i]));
puts(names[i]);
}
for (i = 0; i < counter; i++) {
if (names[i] != NULL)
free(names[i]);
}
if (names != NULL)
free(names);
return 0;
}
This:
names = (char**)malloc(77 * sizeof(char));
is wrong, sizeof (char) is 1 which is not what you want.
It should be:
names = malloc(77 * sizeof *names);
This is the same as 77 * sizeof (char *) since names is char ** which makes the type of *names be char *.
The cast is not necessary and should be omitted in my opinion.
It's very strange (and an obvious code smell) to use a literal 77 instead of count for the array length, of course.
You probably want names = (char**)malloc(counter * sizeof(char*));.
Also free handles null pointers, no need to check the pointer for null before calling it.
Related
I'm trying to create a program which the user inputs the number of items (rows) and give each one of them a name (scanf) with the max of 30 characters.
I want to create this code with pointers of pointers, once that I'm learning this on C.
I'm having some difficulties with the code.
Draft of the 2D array.
Code snippet:
PS: #define MAX 31
char **items = NULL, *columns = NULL, name[MAX];
int rows, aux_rows;
printf("\nNumber of items:\n");
scanf("%d", &rows);
items = (char **) malloc(rows * sizeof(char*));
for (aux_rows = 0; aux_rows < rows; aux_rows++){
columns[aux_rows] = (char *) malloc(MAX * sizeof(char));
}
for (aux_rows = 0; aux_rows < rows; aux_rows++){
printf("\nName of item %d:\n", (aux_rows + 1));
scanf("%s", name);
*items[aux_rows] = name;
}
items was allocated and not columns. And use strcpy to copy the characters.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 31
int main()
{
char **items = NULL, *columns = NULL, name[MAX];
int rows, aux_rows;
printf("\nNumber of items:\n");
scanf("%d", &rows);
items = (char **)malloc(rows * sizeof(char *));
for (aux_rows = 0; aux_rows < rows; aux_rows++)
{
items[aux_rows] = malloc(MAX * sizeof(char));
}
for (aux_rows = 0; aux_rows < rows; aux_rows++)
{
printf("\nName of item %d:\n", (aux_rows + 1));
scanf("%s", name);
strcpy(items[aux_rows], name);
}
return 0;
}
$ gcc array2d.c
$ ./a.out
Number of items:
2
Name of item 1:
Hello
Name of item 2:
World!
$
*items[aux_rows] = name;
is wrong on two counts.
Both * and [] dereference their unary operand. If items is a char **, items[n] is a char *, and *items[n] is a char.
This attempts to assign an array to the first element of each buffer.
Secondly, arrays cannot be copied by assignment. Use strcpy to copy strings from one buffer to another.
That said, you could simply read your strings directly into the pre-allocated buffers, and do away with the temporary buffer.
In this line,
columns[aux_rows] = (char *) malloc(MAX * sizeof(char));
columns should be items.
Some things of note:
sizeof (char) is guaranteed to be 1. Its use is superfluous.
The return of malloc should not be cast in C.
malloc can fail. scanf can fail. You should get in the habit of not ignoring return values.
scanf("%s", ...) is as dangerous as gets. At a minimum, use field-width specifiers to limit input (should be the size of your buffer minus one).
char foo[128];
if (1 != scanf("%127s", foo))
/* handle error */;
Note that using the %s limits input to not contain any whitespace. scanf in general is a terrible tool, consider a line based approach using fgets.
With that said, the minimum changes to make this reasonably safe:
#include <stdio.h>
#include <stdlib.h>
#define MAX 31
void die(const char *msg)
{
fprintf(stderr, "%s\n", msg);
exit(EXIT_FAILURE);
}
int main(void)
{
size_t rows;
printf("Number of items: ");
if (1 != scanf("%zu", &rows))
die("Failed to read input.");
char **items = malloc(sizeof *items * rows);
if (!items)
die("Failed to allocate memory.");
for (size_t i = 0; i < rows; i++) {
if (!(items[i] = malloc(MAX)))
die("Failed to allocate row.");
printf("Name of item %zu: ", i + 1);
if (1 != scanf("%30s", items[i]))
die("Failed to read item input.");
}
for (size_t i = 0; i < rows; i++) {
puts(items[i]);
free(items[i]);
}
}
Can you give me advice to correct my code? It should initialize new_string from another string, with copying the n first letters from this string. Output should be string. But my code prints nothing. How can I fix it?
Here is my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char str[99];
int n, i, len;
printf("Enter a string:");
scanf("%s", str);
printf("enter n:");
scanf("%i", &n);
if (n > len) {
n = len;
}
char *new_string = malloc(n + 1);
for (int i = 0; i < n; i++) {
new_string[i] = str[i];
}
new_string[i] = '\0';
printf("STring:%s", new_string);
return 0;
}
You could use strncpy as suggested by d.j.yotta in the comments:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (void)
{
char str[100];
printf("Enter string: ");
/*
* take spaces into account (optional),
* prevent buffer overflow and
* check return value of `scanf`
*/
if (scanf("%99[^\n]", str) != 1) {
fprintf(stderr, "Error: invalid input\n");
return EXIT_FAILURE;
}
int n;
printf("Enter index: ");
/* check return value of `scanf` */
if(scanf("%d", &n) != 1) {
fprintf(stderr, "Error: invalid input\n");
return EXIT_FAILURE;
}
/* initialize `len` */
int len = strlen(str);
if (n > len)
n = len;
char *new_str = malloc(n + 1);
strncpy(new_str, str, n);
printf("New string: %s\n", new_str);
return EXIT_SUCCESS;
}
Or you could make the changes explained in the following code's comments:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (void)
{
char str[99];
printf("Enter string: ");
/*
* take spaces into account (optional),
* prevent buffer overflow and
* check return value of `scanf`
*/
if (scanf("%99[^\n]", str) != 1) {
fprintf(stderr, "Error: invalid input\n");
return EXIT_FAILURE;
}
int n;
printf("Enter index: ");
/* check return value of `scanf` */
if(scanf("%d", &n) != 1) {
fprintf(stderr, "Error: invalid input\n");
return EXIT_FAILURE;
}
/* initialize `len` */
int len = strlen(str);
if (n > len)
n = len;
char *new_str = malloc(n + 1);
for (int i = 0; i < n; ++i)
new_str[i] = str[i];
/* you don't need `i` here */
new_str[n + 1]= '\0';
printf("New string: %s\n", new_str);
return EXIT_SUCCESS;
}
The problem in your code is not easy to spot: you define two distinct local variables named i: one in the scope of the body of the main function in int n,i, len; and another one in the scope of the for loop: for (int i = 0; i < n; i++) { new_string[i] = str[i]; }. The latter one goes out of scope at the end of the loop and the first one is used to set the null terminator new_string[i]='\0';. This i variable is uninitialized so the statement has undefined behavior and new_string is not properly null terminated.
There are other problems:
you do not prevent buffer overflow in scanf("%s",str);
you do not check for input or conversion failure in scanf().
n is uninitialized in if (n > len) { n = len; }
you do not check for negative n.
you do check for allocation failure after char *new_string = malloc(n + 1);
you do not free new_string after use.
Here is a modified version:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char str[100];
int n, len;
printf("Enter a string:");
if (scanf("%99s", str) != 1)
return 1;
printf("enter n:");
if (scanf("%i", &n) != 1)
return 1;
len = strlen(str);
if (n > len) {
n = len;
} else
if (n < 0) {
n = 0;
}
char *new_string = malloc(n + 1);
if (new_string == NULL) {
fprintf(stderr, "allocation failure for %d bytes\n", n);
return 1;
}
for (int i = 0; i < n; i++) {
new_string[i] = str[i];
}
new_string[n] = '\0';
printf("String: %s\n", new_string);
free(new_string);
return 0;
}
Note also some alternatives to copy at most n characters from a string:
// assuming new_string points to an array of at least n+1 bytes
strncpy(new_string, str, n);
// assuming new_string points to an array of at least n+1 bytes
snprintf(new_string, n + 1, "%s", str);
// assuming new_string points to an array of at least new_string_size bytes
// and n has type int
snprintf(new_string, new_string_size, "%.*s", n, str);
Since you know that n >= 0 && n <= len, you can use memcpy:
memcpy(new_string, str, n);
new_string[n] = '\0';
You can also use the Posix function strndup() defined in <string.h> that combines allocating enough space, copying at most n bytes and setting the null terminator:
char *new_string = strndup(str, n);
strndup() will be part of the upcoming version of the C Standard (C2x) and is widely available on most platforms as it has been part of the Posix standard for more than 10 years.
#include <stdio.h>
#define N 100
int main(){
char str[N];
scanf("%s",str);
char str1[N];
int i;
for(i=0;i<N;i++){
str1[i]=str[i];
}
printf("%s",str1);
}
i think if you just want to copy a string in a new char variable you can do this please tell if you find anything wrong
I'm trying to build in C an array of structures without defining the length of the maximum size of the array.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct text {
char *final;
} text;
int main() {
int n, sizearray = 10, i;
char *str;
text *testo;
testo = (text *)malloc(sizeof(text) * sizearray);
fgets(str, 1024, stdin);
i = 0;
while (str[0] != 'q') {
if (i == sizearray - 1) {
testo = (text *)realloc(testo, sizearray * 2 * sizeof(text));
}
n = strlen(str);
n = n + 1;
testo[i].finale = (char *)malloc(sizeof(char) * n);
strcpy(testo[i].finale, str);
i++;
fgets(str, 1024, stdin);
}
for (i = 0; i < sizearray; i++)
printf("%s \n", testo[i].finale);
return 0;
}
this gives me
process finished with exit code 139 (interrupted by signal 11:SIGSEV).
What am I doing wrong?
There are multiple issues in your code:
[major] str is an uninitialized pointer. You should make it an array of char defined with char str[1024].
[major] you do not adjust sizearray when you double the size of the array, hence you will never reallocate the array after the initial attempt at i = 9.
[major] the final loop goes to sizearray but there are potentially many uninitialized entries at the end of the array. You should stop at the last entry stored into the array.
you should also check the return value of fgets() to avoid an infinite loop upon premature end of file.
you should test for potential memory allocation failures to avoid undefined behavior.
Here is a modified version:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct text {
char *finale;
} text;
int main() {
char str[1024];
text *testo = NULL;
size_t sizearray = 0;
size_t i, n = 0;
while (fgets(str, sizeof str, stdin) && *str != 'q') {
if (n == sizearray) {
/* increase the size of the array by the golden ratio */
sizearray += sizearray / 2 + sizearray / 8 + 10;
testo = realloc(testo, sizearray * sizeof(text));
if (testo == NULL) {
fprintf(stderr, "out of memory\n");
return 1;
}
}
testo[n].finale = strdup(str);
if (testo[n].finale == NULL) {
fprintf(stderr, "out of memory\n");
return 1;
}
n++;
}
for (i = 0; i < n; i++) {
printf("%s", testo[i].finale);
}
for (i = 0; i < n; i++) {
free(testo[i].finale);
}
free(testo);
return 0;
}
str is uninitialized. Either allocate memory with malloc or define it as an array with char str[1024].
I am new to arrays with pointers, and I am trying to make an array of pointers word scramble game that allows 3 tries to guess the word before the game ends. Basically, I have created a function that scrambles a string. Then, that string is sent to a new string, which is shown to the user. The user then enters their guess. I am getting no signal from my compiler on what is wrong.. It just crashes when it is run. I believe the error is when I am sending the pointer to the method. Could someone please tell me why this error is happening? Thanks.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
void scramble(char *strings)
{
int length = strlen(strings), i, randomNum;
char temp;
for(i = 0; i < length/2; i++)
{
randomNum = rand()%length;
temp = strings[i];
strings[i] = strings[length - randomNum];
strings[length - randomNum] = temp;
}
}
int main()
{
int i, tries, NUMWORDS;
char *words[] = { "pumpkin", "cantalope", "watermelon", "apple", "kumquat" };
char *scramWords, *user;
NUMWORDS = strlen(words);
srand(time(NULL));
for(i = 0; i < NUMWORDS; i++)
{
scramWords[i] = words[i];
scramble(scramWords[i]);
}
printf("How to play: You get 3 tries to guess each scrambled word.\n");
for(i = 0; i < NUMWORDS; i++)
{
tries = 0;
while(tries !=4)
{
if(tries == 3)
{
printf("You Lose\n");
return 0;
}
printf("Unscramble: %s\n", scramWords[i]);
gets(user);
if(strcmp(user, words[i]) == 0)
{
printf("Correct!\n");
break;
}
else
{
tries++;
}
}
}
printf("You Win!");
return 0;
}
You must not try to modify string literals, or you will invoke undefined behavior. Copy strings before editing them instead of just assigning pointers.
length - randomNum may be length when randomNum is 0.
strlen(words) won't be the number of elements in words. You can use sizeof(words) / sizeof(*words).
You must allocate some buffer to scramWords and user before writing anything there.
You shouldn't use gets(), which has unavoidable risk of buffer overrun, deprecated in C99 and removed from C11.
Try this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
void scramble(char *strings)
{
int length = strlen(strings), i, randomNum;
char temp;
for(i = 0; i < length/2; i++)
{
randomNum = rand()%length;
temp = strings[i];
strings[i] = strings[length - randomNum - 1];
strings[length - randomNum - 1] = temp;
}
}
int main(void)
{
int i, tries, NUMWORDS;
char *words[] = { "pumpkin", "cantalope", "watermelon", "apple", "kumquat" };
char **scramWords, user[1024], *lf;
NUMWORDS = sizeof(words) / sizeof(*words);
srand(time(NULL));
scramWords = malloc(sizeof(*scramWords) * NUMWORDS);
if(scramWords == NULL)
{
perror("malloc");
return 1;
}
for(i = 0; i < NUMWORDS; i++)
{
scramWords[i] = malloc(strlen(words[i]) + 1); /* +1 for terminating null-character */
if(scramWords[i] == NULL)
{
perror("malloc");
return 1;
}
strcpy(scramWords[i], words[i]);
scramble(scramWords[i]);
}
printf("How to play: You get 3 tries to guess each scrambled word.\n");
for(i = 0; i < NUMWORDS; i++)
{
tries = 0;
while(tries !=4)
{
if(tries == 3)
{
printf("You Lose\n");
return 0;
}
printf("Unscramble: %s\n", scramWords[i]);
if(fgets(user, sizeof(user), stdin) == NULL)
{
puts("fgets failed");
return 1;
}
if((lf = strchr(user, '\n')) != NULL)
{
*lf = '\0'; /* remove newline character after string read */
}
if(strcmp(user, words[i]) == 0)
{
printf("Correct!\n");
break;
}
else
{
tries++;
}
}
}
printf("You Win!");
return 0;
}
you have a few issues in your code:
1), scramblegets a char * but here
scramWords[i] = words[i];
scramble(scramWords[i]);
you provide it with a char so define your scramWords as a char** instead of char*
2) You don't allocate space when declaring a pointer - that could lead to segfault. Use malloc or before accessing the pointer.
3) When assigning strings from one pointer to another use strcpy, not = operator
4) Use sizeof(words)/sizeof(*words) instead of NUMWORDS = strlen(words);
That should leave you with a working piece of code, but, as said in comments - take care of your warnings!
Silly little C program, but for the life of me I can't figure out why I keep getting a segmentation fault. I believe I'm allocating enough memory with malloc. Any help would be much appreciated. The code is supposed to read a day of the month and 'reminder' string from the user, and then reads these into data pointed to by the array reminders and allocated memory space with malloc.
/* Prints a one-month reminder list (dynamic string version) */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_REMIND 50 /* maximum number of reminders */
#define MSG_LEN 60 /* maximum length of reminder message */
int read_line(char str[], int n);
int main(void)
{
char *reminders[MAX_REMIND];
char day_str[3], msg_str[MSG_LEN+1];
int day, i, j, num_remind = 0;
for (;;) {
if (num_remind == MAX_REMIND) {
printf("-- no space left --\n");
break;
}
printf("Enter day and reminder: ");
scanf("%2d", &day);
if (day == 0) {
break;
}
sprintf(day_str, "%2d", day);
read_line(msg_str, MSG_LEN);
for (i = 0; i < num_remind; i++) {
if (strcmp(day_str, reminders[i]) < 0) {
break;
}
}
for (j = num_remind; j > i; j--) {
reminders[j] = reminders[j-1];
}
reminders[i] = malloc(2 + strlen(msg_str) + 10);
if (reminders[i] = NULL) {
printf("-- No Space Left --\n");
break;
}
strcpy(reminders[i], day_str);
strcat(reminders[i], msg_str);
num_remind++;
}
printf("\nDay Reminder\n");
for (i = 0; i < num_remind; i++) {
printf(" %s\n", reminders[i]);
}
return 0;
}
int read_line(char str[], int n) {
int ch, i = 0;
while ((ch = getchar()) != '\n') {
if (i < n) {
str[i++] = ch;
}
}
str[i] = '\0';
return i;
}
if (reminders[i] = NULL) {
You set reminders[i] to NULL before you dereference it.
The dreaded assignment/comparison typo! This is a hint that your compiler warning levels are not set high enough or that you are ignoring the warnings.
// Should be '==' not '='
if (reminders[i] = NULL) {
printf("-- No Space Left --\n");
break;
}
Also, your read_line function is similar to fgets, which may simplify things.
Lastly, always validate your user input. Make sure scanf returns the number of items that you've asked for (usually 1 for simple one-item input). Otherwise, you're likely to venture into undefined behaviour.
wrong:
if (reminders[i] = NULL) {
right:
if (reminders[i] == NULL) {
also, you are concatenating day_str & msg_str, so it's better to alloc:
reminders[i] = malloc(2 + strlen(msg_str) + strlen(day_str));
You are doing assignment in if clause. It should be like this:
if (reminders[i] == NULL) {
printf("-- No Space Left --\n");
break;
}