How to add this information to an array? - c

I've got this project in C and the code looks like this.
BOOL Commands(LPBYTE command, DWORD size)
{
wchar_t params[MAXCHAR];
MultiByteToWideChar(CP_ACP, MB_COMPOSITE, (LPCCH)command, size, params, size);
wchar_t *bufferoon;
bufferoon = (wchar_t *)malloc(sizeof(wchar_t) * size);
wcscpy(bufferoon, params);
wchar_t buf2[MAXCHAR], *ptr;
int i;
wchar_t a[MAXCHAR];
for (ptr = wcstok(bufferoon, L","); ptr != NULL; ptr = wcstok(NULL, L","))
{
CWA(lstrcpyW, kernel32, buf2, ptr);
for (i = 0; i < lstrlenW(buf2); i++)
{
if (buf2[i] == '=' )
{
wcscpy(a + i, buf2 + i + 1);
MessageBoxW(0, a + i, 0, 0);
}
}
}
free(bufferoon);
CWA(Sleep, kernel32, 100);
return 1;
}
It gets a string from a PHP page and then splits it, removes the "=" and some junk before the "=" and and displays the important datas in MessageBoxes one by one and it works well.
However, instead of showing it in messageboxes, I want to create an array with all the data.
For example, some of the data returned as "a + i" will include:
1. https
2. //test.com/test.doc
3. H3IG2IOUFG23IOFGU2H3
Etc.
I want to create an array, so I can use it to make if-statements.
For example, I want to be able to do something like:
if(strarray[1] == L"https")
{
MessageBoxW(0,L"Element 1 equals HTTPS",0,0);
}
However, after trying a million things for hours and hours, I have still no clue, so I am asking you guys on StackOverflow as a last resort.
Does anyone have an idea? My brain is fried by now, I would really appreciate it if someone could help me out.
Thanks in advance!

If you want to use an array, you need to know the size. You have two choices:
1) Allocate an array of N elements using malloc (just pick some number N), populate the array, and increment your size variable. If size exceeds N, you will need to realloc with a bigger N.
2) Perform two loops. The first loop counts the number of array elements. After the first loop ends, use malloc to allocate the array knowing the size. Then perform a second loop to populate the array.
int N=0;
wchar_t *saved = wcsdup(bufferoon);
for (ptr = wcstok(bufferoon, L","); ptr != NULL; ptr = wcstok(NULL, L","))
{
for (i = 0; i < lstrlenW(ptr); i++)
{
if (ptr[i] == '=' )
{
++N;
break;
}
}
}
int j=0;
wchar_t **a = malloc(N*sizeof(*a));
for (ptr = wcstok(saved, L","); ptr != NULL; ptr = wcstok(NULL, L","))
{
for (i = 0; i < lstrlenW(ptr); i++)
{
if (ptr[i] == '=' )
{
a[j++] = wcsdup(ptr+i+1);
break;
}
}
}
free(saved);

Related

last number in a function array

I want to write a function where I have a given array and number N. The last occurrence of this number I want to return address. If said number cannot be found I want to use a NULL-pointer
Start of the code I've made:
int main(void) {
int n = 3;
int ary[6] = { 1,3,7,8,3,9 };
for (int i = 0; i <= 6; i++) {
if (ary[i] == 3) {
printf("%u\n", ary[i]);
}
}
return 0;
}
result in command prompt:
3
3
The biggest trouble I'm having is:
it prints all occurrences, but not the last occurrence as I want
I haven't used pointers much, so I don't understand how to use the NULL-pointer
I see many minor problems in your program:
If you want to make a function, make a function so your parameters and return types are explicit, instead of coding directly in the main.
C arrays, like in most languages, start the indexing at 0 so if there are N element the first has index 0, then the second has 1, etc... So the very last element (the Nth) has index N-1, so in your for loops, always have condition "i < size", not "i <= size" or ( "i <= size-1" if y'r a weirdo)
If you want to act only on the last occurence of something, don't act on every. Just save every new occurence to the same variable and then, when you're sure it was the last, act on it.
A final version of the function you describe would be:
int* lastOccurence(int n, int* arr, int size){
int* pos = NULL;
for(int i = 0; i < size; i++){
if(arr[i] == n){
pos = &arr[i]; //Should be equal to arr + i*sizeof(int)
}
}
return pos;
}
int main(void){
int n = 3;
int ary[6] = { 1,3,7,8,3,9 };
printf("%p\n", lastOccurence(3, ary, 6);
return 0;
}
Then I'll add that the NULL pointer is just 0, I mean there is literally the line "#define NULL 0" inside the runtime headers. It is just a convention that the memory address 0 doesn't exist and we use NULL instead of 0 for clarity, but it's exactly the same.
Bugs:
i <= 6 accesses the array out of bounds, change to i < 6.
printf("%u\n", ary[i]); prints the value, not the index.
You don't actually compare the value against n but against a hard-coded 3.
I think that you are looking for something like this:
#include <stdio.h>
int main(void)
{
int n = 3;
int ary[6] = { 1,3,7,8,3,9 };
int* last_index = NULL;
for (int i = 0; i < 6; i++) {
if (ary[i] == n) {
last_index = &ary[i];
}
}
if(last_index == NULL) {
printf("Number not found\n");
}
else {
printf("Last index: %d\n", (int)(last_index - ary));
}
return 0;
}
The pointer last_index points at the last found item, if any. By subtracting the array's base address last_index - ary we do pointer arithmetic and get the array item.
The cast to int is necessary to avoid a quirk where subtracting pointers in C actually gives the result in a large integer type called ptrdiff_t - beginners need not worry about that one, so just cast.
First of all, you will read from out of array range, since your array last element is 5, and you read up to 6, which can lead in segmentation faults. #Ludin is right saying that you should change
for (int i = 0; i <= 6; i++) // reads from 0 to 6 range! It is roughly equal to for (int i = 0; i == 6; i++)
to:
for (int i = 0; i < 6; i++) // reads from 0 to 5
The last occurrence of this number I want to return as address.
You are printing only value of 3, not address. To do so, you need to use & operator.
If said number cannot be found I want to use a NULL-pointer
I don't understand, where do you want to return nullpointer? Main function can't return nullpointer, it is contradictory to its definition. To do so, you need to place it in separate function, and then return NULL.
If you want to return last occurence, then I would iterate from the end of this array:
for (int i = 5; i > -1; i--) {
if (ary[i] == 3) {
printf("place in array: %u\n", i); // to print iterator
printf("place in memory: %p\n", &(ary[i])); // to print pointer
break; // if you want to print only last occurence in array and don't read ruther
}
else if (i == 0) {
printf("None occurences found");
}
}
If you want to return an address you need yo use a function instead of writing code in main
As you want to return the address of the last occurence, you should iterate the array from last element towards the first element instead of iterating from first towards last elements.
Below are 2 different implementations of such a function.
#include <stdio.h>
#include <assert.h>
int* f(int n, size_t sz, int a[])
{
assert(sz > 0 && a != NULL);
// Iterate the array from last element towards first element
int* p = a + sz;
do
{
--p;
if (*p == n) return p;
} while(p != a);
return NULL;
}
int* g(int n, size_t sz, int a[])
{
assert(sz > 0 && a != NULL);
// Iterate the array from last element towards first element
size_t i = sz;
do
{
--i;
if (a[i] == n) return &a[i];
} while (i > 0);
return NULL;
}
int main(void)
{
int n = 3;
int ary[] = { 1,3,7,8,3,9 };
size_t elements = sizeof ary / sizeof ary[0];
int* p;
p = g(n, elements, ary); // or p = f(n, elements, ary);
if (p != NULL)
{
printf("Found at address %p - value %d\n", (void*)p, *p);
}
else
{
printf("Not found. The function returned %p\n", (void*)p);
}
return 0;
}
Working on the specified requirements in your question (i.e. a function that searches for the number and returns the address of its last occurrence, or NULL), the code below gives one way of fulfilling those. The comments included are intended to be self-explanatory.
#include <stdio.h>
// Note that an array, passed as an argument, is converted to a pointer (to the
// first element). We can change this in our function, because that pointer is
// passed BY VALUE (i.e. it's a copy), so it won't change the original
int* FindLast(int* arr, size_t length, int find)
{
int* answer = NULL; // The result pointer: set to NULL to start off with
for (size_t i = 0; i < length; ++i) { // Note the use of < rather than <=
if (*arr == find) {
answer = arr; // Found, so set our pointer to the ADDRESS of this element
// Note that, if multiple occurrences exist, the LAST one will be the answer
}
++arr; // Move on to the next element's address
}
return answer;
}
int main(void)
{
int num = 3; // Number to find
int ary[6] = { 1,3,7,8,3,9 }; // array to search
size_t arrlen = sizeof(ary) / sizeof(ary[0]); // Classic way to get length of an array
int* result = FindLast(ary, arrlen, num); // Call the function!
if (result == NULL) { // No match was found ...
printf("No match was found in the array!\n");
}
else {
printf("The address of the last match found is %p.\n", (void*)result); // Show the address
printf("The element at that address is: %d\n", *result); // Just for a verification/check!
}
return 0;
}
Lots of answers so far. All very good answers, too, so I won't repeat the same commentary about array bounds, etc.
I will, however, take a different approach and state, "I want to use a NULL-pointer" is a silly prerequisite for this task serving only to muddle and complicate a very simple problem. "I want to use ..." is chopping off your nose to spite your face.
The KISS principle is to "Keep It Simple, St....!!" Those who will read/modify your code will appreciate your efforts far more than admiring you for making wrong decisions that makes their day worse.
Arrays are easy to conceive of in terms of indexing to reach each element. If you want to train in the use of pointers and NULL pointers, I suggest you explore "linked lists" and/or "binary trees". Those data structures are founded on the utility of pointers.
int main( void ) {
const int n = 3, ary[] = { 1, 3, 7, 8, 3, 9 };
size_t sz = sizeof ary/sizeof ary[0];
// search for the LAST match by starting at the end, not the beginning.
while( sz-- )
if( ary[ sz ] == n ) {
printf( "ary[ %sz ] = %d\n", sz, n );
return 0;
}
puts( "not found" );
return 1; // failed to find it.
}
Consider that the array to be searched is many megabytes. To find the LAST match, it makes sense to start at the tail, not the head of the array.
Simple...

Can someone please explain why I'm getting a seg fault error

This code compiles successfully but when I debug it shows a SIGSEV seg fault error. Can someone help please?
char *_strdup(char *str)
{
int i, size = 0;
char *mp;
if (str == NULL)
{
return (NULL);
}
for (; str[size] != '0'; size++)
mp = malloc(size * sizeof(str) + 1);
/* + 1 to get last part of the str */
if (mp == 0)
{
return (NULL);
}
else
{
for (; i < size; i++)
{
mp[i] = str[i];
}
}
return (mp);
}
First, just because it compiles successfully, this does not mean that your code is correct. It just means that syntactically the compiler is fine. I hope you use the maximum warning level and correct your code until all warnings and errors are gone.
You have multiple problems:
You seem to look for the terminating end-of-string marker. But instead of the correct '\0' you typed '0'. This can lead to a much too big size, depending where a zero digit is found. Depending on your system, a segmentation fault is also possible.
sizeof is an operator that yields the size of its argument, in your case the size of a pointer. str is of type char *. Effectively you allocate too much, but this is harmless.
The for loop uses the memory allocation as its body. I'm sure you didn't mean this, but there is no empty statement. So you are allocating multiple memory spaces, which are leaks in the end.
An empty statement is a single semicolon or an empty pair of curly braces.
What you most probably want to achieve is to find the number of characters that str points to. You can get it by calling strlen(str).
i is not initialized, it can have any value. This can lead to a segmentation fault, if it starts with a negative value.
You did not add the end-of-string marker in the duplicate. Depending on the other code we don't see, this can lead to segmentation faults.
This is a possible solution without calling strlen():
char *_strdup(const char *str)
{
int i;
int size;
char *mp;
if (str == NULL)
{
return NULL;
}
for (size = 0; str[size] != '\0'; size++)
{
/* just looking for the end of the string */
}
size++;
/* + 1 for the end-of-string marker */
mp = malloc(size);
if (mp == NULL)
{
return NULL;
}
for (i = 0; i < size; i++)
{
mp[i] = str[i];
}
return mp;
}
I made a bit more:
Use separate variable definitions, it avoid errors and eases maintenance.
return is not a function and needs no parentheses for its expression.
Put the initialization of the index variable where it belongs, in the initializing statement of for. This way everything about this index is at one place.
Consider the end-of-string marker by incrementing size. This eases the following code.
Since sizeof (char) is 1, it can be ommitted at the calculation of the needed memory size.
Compare mp with NULL instead of 0. It is a pointer, and this is C, not C++.
Your variable i has been declared but not initialized so a random number is used in your for(; i < size;
Just add int i = 0, size = 0; at the beginning or change your for statement to for(i = 0; i < size; i++)
This was the reason for your segmentation fault. Some other issues:
As mentioned in comments string termination character is not '0'. It's either 0 or '\0'.
You are calling malloc on each iteration of your for statement. This causes memory leak.Just call it once after you got your string size right. This is fixed by putting a semicolon after the for.
Maybe something like this.
char *_strdup (char *str)
{
int i, size;
char *mp;
if (str == NULL)
{
return (NULL);
}
for (size = 0; str[size] != 0; size++);
mp = malloc (size * sizeof (str) + 1);
/* + 1 to get last part of the str */
if (mp == 0)
{
return (NULL);
}
else
{
for (i = 0; i < size; i++)
{
mp[i] = str[i];
}
}
return (mp);
}

Bubble sort on string array not doing anything in C with strcmp

I am trying to sort a string array in C (char**), the string array is an array of all the names of files in a directory.
Here are all the parts of the code, I expect the code to sort the array alphabetically, but it doesn't work.
Here is the code to get the files from the directory
typedef struct
{
char** names;
int32_t count;
} Files;
void swap(char* a, char* b)
{
char* temp = a;
a = b;
b = temp;
}
void bubbleSort(char** strs, uint32_t length)
{
uint32_t i = 0, j = 0;
for (i = 0; i < length; i++)
{
for (j = 0; j < length - i - 1; j++)
{
if (strcmp(strs[j], strs[j + 1]) < 0)
{
swap(strs[j], strs[j + 1]);
}
}
}
}
Files* getScannableFilesInDir(char* dirname)
{
Files* files = (Files*)malloc(sizeof(Files));
files->names = NULL; //clearing garbage values
files->count = 0; //clearing garbage values
uint32_t dirnameLength = strlen(dirname);
uint32_t count = 0;
uint32_t countIterations = 0;
DIR* d = opendir(dirname);
struct dirent* dir = NULL;
while ((dir = readdir(d)) != NULL)
{
if (files->names == NULL) //first file, if START_AMOUNT is set to 0 we want to allocate enough space for the first path, once we know there is at least 1 file
{
files->names = (char**)malloc(1 * sizeof(char*));
count++; // there is enough space allocated for 1 string
}
if (strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..") && dir->d_type != DT_DIR)
{
++countIterations;
if (count < countIterations)
{
files->names = (char**)realloc(files->names, countIterations * sizeof(char*)); //adding 1 more space
}
files->names[countIterations - 1] = (char*)malloc(sizeof(char) * (strlen(dir->d_name) + dirnameLength) + 2); //-1 because we are incrementing at the start of the loop and not the end
//+ 2 at the end because a. the \0 at the end, b. 1 space for adding the slash
strcpy(files->names[countIterations - 1], dirname);
files->names[countIterations - 1][dirnameLength] = '/'; //changing the \0 to /
strcpy(files->names[countIterations - 1] + (dirnameLength + 1), dir->d_name); //adding the name after the /, now we have the full name
}
}
closedir(d);
files->count = countIterations;
bubbleSort(files->names, files->count);
return files;
}
I checked the rest of the code, I am not changing the value of the files->names at any other point of the code, just reading it.
You swap, and the way it is invoked from bubblesort, are both wrong. First let me educate you on a simple fundamental.
Arguments in C are pass-by-value. The only way to change caller-side data from an argument passed to a function as a parameter is to change the fundamentals of the parameter. You'll still pass by-value, you just need to make the "value" something you can use to access the caller's variable data. In C, you do that by declaring the formal parameter to be a pointer-to-type, pass the address of the thing you want changed caller-side, and within the function use the pointer via dereference to instigate the change.
void foo(int *a)
{
*a = 42; // stores 42 in whatever 'a' points to
}
Now, lets take a look at your swap:
void swap(char* a, char* b)
{
char* temp = a;
a = b;
b = temp;
}
Well, we have two pointers. But nowhere in this code do we actually dereference anything. All we're doing is swapping the values of the two pointers locally. The caller is completely unaffected by any of this.
What your swap is supposed to be doing is swapping two pointers. We have two char* caller side values we want to swap. The way to do that is exactly as we discussed before. Declare the formal parameters to be pointer-to-type (our type is char*, so our parameters are char**), then use dereferencing to modify the caller-side data.
void swap(char **ppA, char **ppB)
{
char *pp = *ppA;
*ppA = *ppB;
*ppB = pp;
}
That will swap two pointers, but only if the caller passes us the addresses of the two pointers. Note the vernacular here. I did not say "passes us the addresses in the two pointers" (e.g. their values), I said "passes us the addresses of the two pointers" (e.g. where the pointers themselves reside in memory). That means bubblesort needs changing too:
void bubbleSort(char** strs, uint32_t length)
{
uint32_t i = 0, j = 0;
for (i = 0; i < length; i++)
{
for (j = 0; j < length - i - 1; j++)
{
if (strcmp(strs[j], strs[j + 1]) < 0)
{
swap(strs+j, strs+j+1); // <=== HERE
}
}
}
}
This passes the addresses of the pointers at str[j] str[j+1] to the swap function.
That should solve your swap issue. Whether the algorithm is correct, or for that matter the rest of your code, I leave to you to digest.

Using pointers in 2D arrays

I'm attempting to store arrays of integers that I read from a file (with a separate function) in a 2D array but I keep having issues with Segmentation fault. I know it's an issue with my pointers but I can't figure out exactly what I'm doing wrong.
Here is my function (takes an integer and compares it with an integer read from a file before storing it in my 2D array).
int **getStopTimes(int stop_id) {
int **result = malloc(sizeof(*result));
char const* const fileName = "stop_times_test.txt";
FILE* txt = fopen(fileName, "r");
char line[256];
int count = 0;
while (fgets(line, sizeof(line), txt) != NULL) {
int *formattedLine = getStopTimeData(line); //getStopTimeData returns a pointer to an array of ints, memory is allocated in the function
if (formattedLine[1] == stop_id) {
result[count] = formattedLine;
count++;
}
}
fclose(txt);
return result;
}
And my main:
int main(int argc, char *argv[]) {
int **niceRow = getStopTimes(21249);
for (int i=0; i<2; i++) { //Only looping 3 iterations for test purposes
printf("%d,%d,%d,%d\n",niceRow[i][0], niceRow[i][1], niceRow[i][2], niceRow[i][3]);
}
free(niceRow);
return 0;
}
getStopTimeData function thats being called (Pulls certain information from an array of chars and stores/returns them in an int array):
int *getStopTimeData(char line[]) {
int commas = 0;
int len = strlen(line);
int *stopTime = malloc(4 * sizeof(*stopTime)); //Block of memory for each integer
char trip_id[256]; //Temp array to build trip_id string
char stop_id[256]; //Temp array to build stop_id string
int arrival_time; //Temp array to build arrival_time string
int departure_time; //Temp array to build departure_time string
int counter;
for(int i = 0; i <len; i++) {
if(line[i] == ',') {
commas++;
counter = 0;
continue;
}
switch(commas) { //Build strings here and store them
case 0 :
trip_id[counter++] = line[i];
if(line[i+1] == ',') trip_id[counter] = '\0';
break;
case 1: //Convert to hours past midnight from 24hr time notation so it can be stored as int
if(line[i] == ':' && line[i+3] == ':') {
arrival_time = (line[i-2]-'0')*600 + (line[i-1]-'0')*60 + (line[i+1]-'0')*10 + (line[i+2]-'0');
}
break;
case 2 :
if(line[i] == ':' && line[i+3] == ':') {
departure_time = (line[i-2]-'0')*600 + (line[i-1]-'0')*60 + (line[i+1]-'0')*10 + (line[i+2]-'0');
}
break;
case 3 :
stop_id[counter++] = line[i];
if(line[i+1] == ',') stop_id[counter] = '\0';
break;
}
}
//Assign and convert to ints
stopTime[0] = atoi(trip_id);
stopTime[1] = atoi(stop_id);
stopTime[2] = arrival_time;
stopTime[3] = departure_time;
return stopTime;
}
This line:
int **result = malloc(sizeof(*result));
allocates just memory for one single pointer. (*result is of type int *, so it's a pointer to data -- the sizeof operator will tell you the size of a pointer to data ... e.g. 4 on a 32bit architecture)
What you want to do is not entirely clear to me without seeing the code for getStopTimeData() ... but you definitely need more memory. If this function indeed returns a pointer to some ints, and it handles allocation correctly, you probably want something along the lines of this:
int result_elements = 32;
int **result = malloc(sizeof(int *) * result_elements);
int count = 0;
[...]
if (formattedLine[1] == stop_id) {
if (count == result_elements)
{
result_elements *= 2;
result = realloc(result, result_elements);
}
result[count] = formattedLine;
count++;
}
Add proper error checking, malloc and realloc could return (void *)0 (aka null) on out of memory condition.
Also, the 32 for the initial allocation size is just a wild guess ... adapt it to your needs (so it doesn't waste a lot of memory, but will be enough for most use cases)
The upper answer is good,
just to give you an advice try to avoid using 2D array but use a simple array where you can store all your data, this ensures you to have coalescent memory.
After that, you can access your 1D array with an easy trick to see it like a 2D array
Consider that your 2D array has a line_size
To access it like a matrix or a 2d array you need to find out the corresponding index of your 1d array for given x,y values
index = x + y * line size;
In the opposite way:
you know the index, you want to find x and y corresponding to this index.
y = index / line_size;
x = index mod(line_size);
Of course, this "trick" can be used if you already know your line size

remove a specified number of characters from a string in C

I can't write a workable code for a function that deletes N characters from the string S, starting from position P. How you guys would you write such a function?
void remove_substring(char *s, int p, int n) {
int i;
if(n == 0) {
printf("%s", s);
}
for (i = 0; i < p - 1; i++) {
printf("%c", s[i]);
}
for (i = strlen(s) - n; i < strlen(s); i++) {
printf("%c", s[i]);
}
}
Example:
s: "abcdefghi"
p: 4
n: 3
output:
abcghi
But for a case like n = 0 and p = 1 it's not working!
Thanks a lot!
A few people have shown you how to do this, but most of their solutions are highly condensed, use standard library functions or simply don't explain what's going on. Here's a version that includes not only some very basic error checking but some explanation of what's happening:
void remove_substr(char *s, size_t p, size_t n)
{
// p is 1-indexed for some reason... adjust it.
p--;
// ensure that we're not being asked to access
// memory past the current end of the string.
// Note that if p is already past the end of
// string then p + n will, necessarily, also be
// past the end of the string so this one check
// is sufficient.
if(p + n >= strlen(s))
return;
// Offset n to account for the data we will be
// skipping.
n += p;
// We copy one character at a time until we
// find the end-of-string character
while(s[n] != 0)
s[p++] = s[n++];
// And make sure our string is properly terminated.
s[p] = 0;
}
One caveat to watch out for: please don't call this function like this:
remove_substr("abcdefghi", 4, 3);
Or like this:
char *s = "abcdefghi";
remove_substr(s, 4, 3);
Doing so will result in undefined behavior, as string literals are read-only and modifying them is not allowed by the standard.
Strictly speaking, you didn't implement a removal of a substring: your code prints the original string with a range of characters removed.
Another thing to note is that according to your example, the index p is one-based, not zero-based like it is in C. Otherwise the output for "abcdefghi", 4, 3 would have been "abcdhi", not "abcghi".
With this in mind, let's make some changes. First, your math is a little off: the last loop should look like this:
for (i = p+n-1; i < strlen(s); i++) {
printf("%c", s[i]);
}
Demo on ideone.
If you would like to use C's zero-based indexing scheme, change your loops as follows:
for (i = 0; i < p; i++) {
printf("%c", s[i]);
}
for (i = p+n; i < strlen(s); i++) {
printf("%c", s[i]);
}
In addition, you should return from the if at the top, or add an else:
if(n == 0) {
printf("%s", s);
return;
}
or
if(n == 0) {
printf("%s", s);
} else {
// The rest of your code here
...
}
or remove the if altogether: it's only an optimization, your code is going to work fine without it, too.
Currently, you code would print the original string twice when n is 0.
If you would like to make your code remove the substring and return a result, you need to allocate the result, and replace printing with copying, like this:
char *remove_substring(char *s, int p, int n) {
// You need to do some checking before calling malloc
if (n == 0) return s;
size_t len = strlen(s);
if (n < 0 || p < 0 || p+n > len) return NULL;
size_t rlen = len-n+1;
char *res = malloc(rlen);
if (res == NULL) return NULL;
char *pt = res;
// Now let's use the two familiar loops,
// except printf("%c"...) will be replaced with *p++ = ...
for (int i = 0; i < p; i++) {
*pt++ = s[i];
}
for (int i = p+n; i < strlen(s); i++) {
*pt++ = s[i];
}
*pt='\0';
return res;
}
Note that this new version of your code returns dynamically allocated memory, which needs to be freed after use.
Here is a demo of this modified version on ideone.
Try copying the first part of the string, then the second
char result[10];
const char input[] = "abcdefg";
int n = 3;
int p = 4;
strncpy(result, input, p);
strncpy(result+p, input+p+n, length(input)-p-n);
printf("%s", result);
If you are looking to do this without the use of functions like strcpy or strncpy (which I see you said in a comment) then use a similar approach to how strcpy (or at least one possible variant) works under the hood:
void strnewcpy(char *dest, char *origin, int n, int p) {
while(p-- && *dest++ = *origin++)
;
origin += n;
while(*dest++ = *origin++)
;
}
metacode:
allocate a buffer for the destination
decalre a pointer s to your source string
advance the pointer "p-1" positions in your source string and copy them on the fly to destination
advance "n" positions
copy rest to destination
What did you try? Doesn't strcpy(s+p, s+p+n) work?
Edit: Fixed to not rely on undefined behaviour in strcpy:
void remove_substring(char *s, int p, int n)
{
p--; // 1 indexed - why?
memmove(s+p, s+p+n, strlen(s) - n);
}
If your heart's really set on it, you can also replace the memmove call with a loop:
char *dst = s + p;
char *src = s + p + n;
for (int i = 0; i < strlen(s) - n; i++)
*dst++ = *src++;
And if you do that, you can strip out the strlen call, too:
while ((*dst++ = *src++) != '\0);
But I'm not sure I recommend compressing it that much.

Resources