I'm using a dynamic array of strings in C:
char** strings;
I initialize it:
int max = 10;
strings = malloc(sizeof(char*) * max);
And copy a couple of dummy strings:
char* str = "dummy";
for (int i = 0; i < max; i++) {
strings[i] = malloc(strlen(str) + 1);
strncpy(strings[i], str, strlen(str) + 1);
}
Yet when I try to print this:
for (int i = 0; i < max; i++)
printf("array = %s", strings[i])
I get this error from Splint:
Value strings[] used before definition
An rvalue is used that may not be initialized to a value on some execution
path. (Use -usedef to inhibit warning)
Checking for NULL like this will not help:
for (int i = 0; i < max; i++)
if (strings[i] != NULL)
printf("array = %s", strings[i])
since strings[i] is still used "before definition".
Any ideas on how to solve this?
Edit: Will try this with a linked list instead, I think.
Also, complete code listing:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char** strings;
int i;
int max = 10;
char* str = "hello";
// Dynamic array with size max
strings = malloc(sizeof(char*) * max);
// Abort if NULL
if (strings == NULL)
return (-1);
// Define strings
for (i = 0; i < max; i++)
{
strings[i] = malloc(strlen(str) + 1);
// Abort if NULL
if (strings[i] == NULL)
{
// Undetected memory leak here!
free(strings);
return (-1);
}
strncpy(strings[i], str, strlen(str) + 1);
}
// Print strings
for (i = 0; i < max; i++)
{
if (strings[i] != NULL)
printf("string[%d] = %s\n", i, strings[i]);
}
// Free strings
for (i = 0; i < max; i++)
{
if (strings[i] != NULL)
free(strings[i]);
}
free(strings);
return 0;
}
I do not have Splint on my machine, so i cannot test with it, just an another way to your task:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int i, len, max;
char* str = "hello";
len = strlen(str) + 1;
max = 10;
char strings[max][len];
for (i = 0; i < max; i++) {
strcpy(strings[i], str);
}
for (i = 0; i < max; i++) {
printf("string[%d] = %s\n", i, strings[i]);
}
return 0;
}
Avoid creating non-continuous memory it would be better approach if you allocate memory in single malloc call.
Memory can be freed in single free call instead of multiple free call
max_rows * sizeof(char) will allocate 2 * 1
((strlen(str) * N) + 1) will allocate memory for every N element.
Here is my approch
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
size_t max_rows = 2;
char* str = "dummpy";
char* vec_s = (char *) malloc( max_rows * sizeof(char) * ((strlen(str) * max_rows) + 1));
for (int i = 0; i < max_rows; i++){
strcpy((vec_s + i), str);
printf("vec_s[%d]=%s\n", i, (vec_s + i));
}
free(vec_s);
return 0;
}
Related
I am currently writing a program to simply reverse a string in C. However, when I try to copy the contents of the temp string I made into the original string, I get a segmentation fault. Also, when I try to free the memory I allocated for my test string I get a warning which says " 'free' called on a pointer to an unallocated object "
Here is my code:
void reverseString(char* str, size_t size) {
char *temp = (char*) malloc(sizeof(str) + 1);
int j = size;
for (int i = 0; i < size; i++) {
temp[i] = str[j];
j--;
}
for (int i = 0; i < size; i++) {
str[i] = temp[i];
}
free(temp);
return;
}
int main() {
char* result = (char*)(malloc(sizeof(char) * 10));
result = "Forty-two";
reverseString(result, strlen(result));
printf("%s", result);
free(result);
result = NULL;
return 0;
}
On the second line, you should be using strlen instead of sizeof, because otherwise you will be allocating space for a character pointer and you need more than that.
sizeof(str) returns size of pointer not length of the literal.
Array index starts from 0. That's why j should starts with (size - 1)
You are allocating memory from heap, use memset before do something.
#bereal already says, if you want to understand more, please check this out :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char* result = (char*)(malloc(sizeof(char) * 10));
memset(result, 0, 10);
printf("Addr of result var : %p \n", result);
result = "Re-assign";
printf("Addr of result var : %p \n", result);
return 0;
}
Maybe my solution gives an idea for you
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void reverseString(char** str, size_t size) {
char *temp = (char*) malloc(size + 1);
memset(temp, 0, size + 1);
int j = size - 1;
for (int i = 0; i < size; i++) {
temp[i] = str[0][j];
j--;
}
//Change addr of holding str
*str = temp;
return;
}
int main() {
char* result = "Forty-two";
reverseString(&result, strlen(result));
printf("%s", result);
//result holds same addr with temp
free(result);
return 0;
}
But there are ways to solve this question more accurately.
This code scans number then he create array with malloc, then i scan strings, i put then inside the array with another malloc, then i sort the strings and print them. I build this code with mallocs and i put array inside array,i have leaks in this code, where i need to put free() function and how i put free()? I tried many times to solve this leaks but its not working.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sort(char** names, int length);
void print_array(char** names, int length);
int main()
{
int num_of_friends = 0;
int i = 0;
char name[50] = { 0 };
char** names = NULL;
printf("Enter number of friends: ");
scanf("%d", &num_of_friends);
getchar();
names = malloc(sizeof(char) * num_of_friends);
for ( i = 0; i < num_of_friends; i++)
{
printf("Enter name of friend %d: ", i + 1);
fgets(name, 50, stdin);
name[strcspn(name, "\n")] = 0;
names[i] = malloc(sizeof(char) * strlen(name));
strcpy(names[i], name);
}
sort(names, num_of_friends);
print_array(names, num_of_friends);
getchar();
return 0;
}
void sort(char** names, int length)
{
char temp[50] = { 0 };
int i = 0;
int j_min = 0;
int j = 0;
for ( i = 0; i < length - 1; i++)
{
j_min = i;
for ( j = i+1; j < length; j++)
{
if (strcmp(names[j], names[j_min]) < 0)
{
j_min = j;
}
}
if (j_min != i)
{
strcpy(temp, names[i]);
strcpy(names[i], names[j_min]);
strcpy(names[j_min], temp);
}
}
}
void print_array(char** names, int length)
{
int i = 0;
for (i = 0; i < length; i++)
{
printf("Friend %d: %s \n", i + 1, names[i]);
}
}
For names, you are allocating sizeof (char) times the user provided number of bytes. This is needs to be sizeof (char *), giving you enough room for each pointer value.
names = malloc(sizeof (char *) * num_of_friends);
You need to allocate one additional byte for the null terminating character ('\0'). sizeof (char) is guaranteed to be 1, making that statement redundant.
names[i] = malloc(strlen(name) + 1);
Before the end of main, you need to free each element of names, and then names itself.
sort(names, num_of_friends);
print_array(names, num_of_friends);
getchar();
for (i = 0; i < num_of_friends; i++)
free(names[i]);
free(names);
return 0;
Your sort function may attempt to copy strings between buffers of differing size. You need to swap pointers instead.
Example:
void swap(char **a, char **b) {
char *c = *a;
*a = *b;
*b = c;
}
void sort(char **names, size_t length) {
for (size_t i = 0; i < length - 1; i++)
for (size_t j = i + 1; j < length; j++)
if (strcmp(names[i], names[j]) > 0)
swap(names + i, names + j);
}
I have an assignment, I need to create a method that receives (char * * ch,site_t size).
ch is an array of addresses to char arrays, I need to make it so that the shortest element will be first (address and place) and longest will be last one (address and place). Here is what made so far although it doesn't work on array size 5 (tried only on size 4):
(Note: I used char * arr[] but I planned to changing it once I get the program working with this type of variable.)
void AdressSwitcher(char * arr[],size_t size){
char*shortest=arr[0];
char*shortestFollower=NULL;
char*longest=arr[1];
char*longestFollower=NULL;
for(size_t i=0;i<size;i++){
if(strlen(arr[i])<(strlen(shortest))){
shortest=arr[i];
arr[i]=arr[0];
}
arr[0]=shortest;
}
for(size_t i=1;i<size;i++){
if(strlen(arr[i])>(strlen(longest))){
longest=arr[i];
arr[i]=arr[size-1];
}
arr[size-1]=longest;
// }
for(size_t i=0;i<size;i++){
printf("%s %p", arr[i],arr[i]);
printf("\n");
}
}
Welcome to SO. This problem can be easily solved with the following method:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *escape_double_quotes(const char *s)
{
char *result = calloc((strlen(s) * 2) + 1, sizeof(char));
size_t resultIndex = 0;
for (size_t i = 0; s[i] != '\0'; i++)
{
if (s[i] == '"')
{
result[resultIndex] = '\\';
resultIndex++;
result[resultIndex] = '"';
resultIndex++;
continue;
}
result[resultIndex] = s[i];
resultIndex++;
}
return result;
}
void longestAndShortest(char **arr, const size_t size)
{
if (size <= 1)
return;
size_t shortIndex = 0;
size_t shortSize = strlen(arr[0]);
size_t longIndex;
size_t longSize = 0;
for (size_t i = 0; i < size; i++)
{
size_t b = strlen(arr[i]);
if (b > longSize)
{
longIndex = i;
longSize = b;
}
if (b < shortSize)
{
shortIndex = i;
shortSize = b;
}
}
printf("The shortest size of the array was %lu, the index of that being %lu and the contents of that being \"%s\".\n", shortSize, shortIndex, escape_double_quotes(arr[shortIndex]));
printf("The longest size of the array was %lu, the index of that being %lu and the contents of that being \"%s\".\n", longSize, longIndex, escape_double_quotes(arr[longIndex]));
return;
}
int main(void)
{
char **array = malloc(sizeof(char*) * 8);
array[0] = malloc(128);
strcpy(array[0], "World!");
array[1] = malloc(128);
strcpy(array[1], "Hello");
longestAndShortest(array, 2);
for (size_t i = 0; i < 2; i++)
free(array[i]);
free(array);
return 0;
}
From here you should be able to complete the rest.
Please work on writing more tidy code. Your future self will thank you.
Have a great day!
The program reads a file which includes one word in every line.After reading random word put random word in a pointer and return the pointer .in main function
printf("%s",func("example.txt",str)) it prints different string when the program run.I want to do this in 2d array(20*20) like table,but i could not imagine how to do this.When i print the the function in internal loop,it give me the same word in every loop step.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char *word(char *file, char *str);
int main() {
char *str ;
int i, j;
str = (char *)malloc(20);
srand(time(NULL));
char *puzzle[20][20];
for (i = 0; i < 20; i++) {
for (j = 0; j < 20; j++) {
puzzle[i][j] = word("words.txt", str);
}
}
for (i = 0; i < 20; i++) {
for (j = 0; j < 20; j++) {
printf("%s ", puzzle[i][j]);
}
printf("\n");
}
}
char *word(char *file, char *str) {
int end, loop, line;
FILE *fd = fopen(file, "r");
if (fd == NULL) {
printf("Failed to open file\n");
return (NULL);
}
srand(time(NULL));
line = rand() % 100 + 1;
for (end = loop = 0; loop < line; ++loop) {
if (0 == fgets(str, 20, fd)) {
end = 1;
break;
}
}
if (!end)
return (char *)str;
fclose(fd);
free(str);
}
I do not have your words.txt file, so I've created some random strings below.
And a note:
Because your nested loop is in the main, your code opens the file in the sub function and returns w/o closing it; then returns to the sub and reopens, and again, and again... It's always better to read at once and close the file before returning from the sub.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char **word(int countString, int maxChars) {
int i;
int j;
int k;
// allocate memory for pointers that are pointing to each string
char **arrStr = malloc(countString * sizeof(char *));
// srand(time(NULL));
for (i = 0; i < countString; i++) {
// create a random string with a length of 'k'
// say, 5 <= k <= maxChars
// that (+ 1) is for the string terminating character '\0'
k = (rand() % (maxChars - 5)) + 5 + 1;
// allocate memory for string
arrStr[i] = malloc(k * sizeof(char));
for (j = 0; j < k - 1; j++) {
*(arrStr[i] + j) = rand() % 26 + 'A';
}
*(arrStr[i] + j) = '\0';
}
return arrStr;
}
int main() {
int countString = 10;
int maxChars = 20;
char **arrStr = NULL;
int i;
arrStr = word(countString, maxChars);
for (i = 0; i < 10; i++) {
printf("%s\n", *(arrStr + i));
}
// do not forget to free the strings
// and then the string pointers (array)
return 0;
}
I'm working on a program that takes command line arguments and splits them in half and then orders them in lexicographical order.
For example:
hello, world!
would turn into:
he
ld!
llo
wor
I have a main method that reads through the arguments, a function that splits the arguments, and finally a function that is supposed to order the halves in lexicographical order. I can't get this to run properly because of argument type errors in the lexicographicalSort method and an incompatible pointer type in the main method. I'm having issues to correct these syntax errors, how exactly would I correct them? Also, is there anything here that would cause logical errors? This is what I have so far:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int splitString(char arg[], int n)
{
int len = strlen(arg);
int len1 = len/2;
int len2 = len - len1; // Compensate for possible odd length
char *s1 = malloc(len1 + 1); // one for the null terminator
memcpy(s1, arg, len1);
s1[len1] = '\0';
char *s2 = malloc(len2 + 1); // one for the null terminator
memcpy(s2, arg + len1, len2);
s2[len2] = '\0';
printf("%s\n", s1);
printf("%s\n", s2);
free(s1);
free(s2);
return 0;
}
int lexicographicalSort(char *arg[], int n)
{
char temp[50];
for(int i = 0; i < n; ++i)
scanf("%s[^\n]",arg[i]);
for(int i = 0; i < n - 1; ++i)
for(int j = i + 1; j < n ; ++j)
{
if(strcmp(arg[i], arg[j]) > 0)
{
strcpy(temp, arg[i]);
strcpy(arg[i], arg[j]);
strcpy(arg[j], temp);
}
}
for(int i = 0; i < n; ++i)
{
puts(arg[i]);
}
return 0;
}
int main(int argc, char *argv[])
{
if (argc > 1)
{
for (int i = 1; i < argc; i++)
{
int j = 1;
int k = strlen(argv[i]);
splitString(argv[i], j);
lexicographicalSort(argv[i], j);
}
}
}
Basic scheme is simple. Make an array of tuples {start_pointer, length}. Do some programming on args to split the args. Fill in the array as appropriate. Make sorting with qsort, or any other sort of your choise.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
char *s = "hello, world! . hello.....";
char *pc;
int i, n, nargs;
struct pp{
char *p;
int l;
};
struct pp args[10], hargs[20];
struct pp *pargs;
int cmp(const void * v0, const void * v1) {
struct pp *pv0 = v0, *pv1 = v1;
return strncmp(pv0->p, pv1->p, pv0->l);
}
int main(void)
{
for(pc = s, i = 0; *pc; ++i){
sscanf(pc, "%*[^ ]%n", &n);
if(n > 0){
args[i].p = pc;
args[i].l = n;
}
for(pc += n, n = 0; isspace(*pc); ++pc);
}
for(nargs = i, i = 0; i < nargs; ++i)
printf("%d arg is: %.*s\n", i, args[i].l, args[i].p);
putchar('\n');
for(i = 0, pargs = hargs; i < nargs; ++i){
if(args[i].l == 1){
pargs->p = args[i].p;
pargs->l = 1;
pargs = pargs + 1;
}else {
pargs->p = args[i].p;
pargs->l = args[i].l / 2;
pargs = pargs + 1;
pargs->p = args[i].p + args[i].l / 2;
pargs->l = args[i].l - args[i].l / 2;
pargs = pargs + 1;
}
}
putchar('\n');
for(nargs = pargs - hargs, i = 0; i < nargs; ++i)
printf("%d arg is: %.*s\n", i, hargs[i].l, hargs[i].p);
qsort(hargs, nargs, sizeof(struct pp), cmp);
putchar('\n');
for(i = 0; i < nargs; ++i)
printf("%d arg is: %.*s\n", i, hargs[i].l, hargs[i].p);
return 0;
}
https://rextester.com/GSH22767
Upon splitting a C string, one needs one extra char to store extra null-terminator. There is one answer that bypasses this by storing the length. For completeness, this is closer to your original intention: allocating enough space to copy the programmes arguments. It probably works slower, but one is free to use the strings elsewhere in the programme.
#include <stdlib.h> /* malloc free EXIT qsort */
#include <stdio.h> /* fprintf */
#include <string.h> /* strlen memcpy */
#include <errno.h> /* errno */
static int strcompare(const void *a, const void *b) {
const char *a_str = *(const char *const*)a, *b_str = *(const char *const*)b;
return strcmp(a_str, b_str);
}
int main(int argc, char **argv) {
char *spacev = 0, **listv = 0;
size_t spacec = 0, listc = 0;
int is_done = 0;
do { /* "Try." */
int i;
char *sv;
size_t j;
/* This requires argc > 1. */
if(argc <= 1) { errno = EDOM; break; }
/* Allocate maximum space. */
for(i = 1; i < argc; i++) spacec += strlen(argv[i]) + 2;
if(!(spacev = malloc(spacec)) || !(listv = malloc(argc * 2))) break;
sv = spacev;
/* Copy and split the arguments. */
for(i = 1; i < argc; i++) {
const char *const word = argv[i];
const size_t word_len = strlen(word),
w0_len = word_len / 2, w1_len = word_len - w0_len;
if(w0_len) {
listv[listc++] = sv;
memcpy(sv, word, w0_len);
sv += w0_len;
*(sv++) = '\0';
}
if(w1_len) {
listv[listc++] = sv;
memcpy(sv, word + w0_len, w1_len);
sv += w1_len;
*(sv++) = '\0';
}
}
/* Sort. */
qsort(listv, listc, sizeof listv, &strcompare);
for(j = 0; j < listc; j++) printf("%s\n", listv[j]);
is_done = 1;
} while(0); if(!is_done) {
perror("split");
} {
free(spacev);
free(listv);
}
return is_done ? EXIT_SUCCESS : EXIT_FAILURE;
}
It is simpler than your original; instead of allocating each string individually, it counts the maximum number of chars needed (plus two for two null terminators) and allocates the block all at once (space.) The pointers to the new list also need allocating, the maximum is 2 * argc. Once you copy and modify the argument list, one has an actual array of strings that one can qsort.